Commit fd43edc5fa5fe34aea96d3d6ffc7ef7e3476970b

Authored by 张志伟
1 parent c752417d

:fire: feat(*): 开发debug接口

- 开发debug接口
fw-hermes-common/src/main/java/cn/fw/hermes/common/constant/Constant.java
... ... @@ -63,4 +63,8 @@ public interface Constant {
63 63 * 更新消息
64 64 */
65 65 String UPDATE_MSG = "UpdateNotice";
  66 + /**
  67 + * 无效信鸽token
  68 + */
  69 + String inValidToken = "#";
66 70 }
... ...
fw-hermes-domain/src/main/java/cn/fw/hermes/domain/db/Hermes.java
... ... @@ -50,6 +50,10 @@ public class Hermes extends BaseAuditableTimeEntity<Hermes, Long> {
50 50 */
51 51 private AccountStateEnum state;
52 52 /**
  53 + * 信鸽设备token
  54 + */
  55 + private String xgToken;
  56 + /**
53 57 * 创建日期
54 58 */
55 59 @JsonDeserialize(using = LocalDateTimeSerializerProcessor.LocalDateDeserializer.class)
... ...
fw-hermes-server/src/main/kotlin/cn/fw/hermes/controller/app/XgController.kt 0 → 100644
  1 +package cn.fw.hermes.controller.app
  2 +
  3 +import cn.fw.common.web.annotation.ControllerMethod
  4 +import cn.fw.common.web.util.ResultBuilder
  5 +import cn.fw.data.base.domain.common.Message
  6 +import cn.fw.hermes.domain.enums.AccountTypeEnum
  7 +import cn.fw.hermes.service.biz.XgPushBizService
  8 +import cn.fw.security.auth.client.annotation.Authorization
  9 +import cn.fw.security.auth.client.annotation.IgnoreAuth
  10 +import cn.fw.security.auth.client.enums.AuthType
  11 +import org.springframework.validation.annotation.Validated
  12 +import org.springframework.web.bind.annotation.PostMapping
  13 +import org.springframework.web.bind.annotation.RequestMapping
  14 +import org.springframework.web.bind.annotation.RequestParam
  15 +import org.springframework.web.bind.annotation.RestController
  16 +
  17 +/**
  18 + * 信鸽相关控制器
  19 + *
  20 + * @author : kurisu
  21 + * @version : 1.0
  22 + * @desc : 信鸽相关控制器
  23 + * @date : 2024-01-05 18:08
  24 + */
  25 +@Validated
  26 +@RestController
  27 +@RequestMapping("/app/xinge")
  28 +@Authorization(AuthType.APP)
  29 +class XgController(private val xgPushBizService: XgPushBizService) {
  30 +
  31 + @IgnoreAuth
  32 + @ControllerMethod("绑定信鸽token")
  33 + @PostMapping("/bind")
  34 + fun bindToken(@RequestParam("userId") userId: Long?, @RequestParam("xgToken") xgToken: String): Message<Void> {
  35 + xgPushBizService.saveUserToken(userId, AccountTypeEnum.B_USER, xgToken)
  36 + return ResultBuilder.success()
  37 + }
  38 +}
... ...
fw-hermes-server/src/main/kotlin/cn/fw/hermes/controller/common/XinGeDebugController.kt
... ... @@ -4,6 +4,7 @@ package cn.fw.hermes.controller.common
4 4 import cn.fw.common.web.annotation.ControllerMethod
5 5 import cn.fw.common.web.util.ResultBuilder.success
6 6 import cn.fw.data.base.domain.common.Message
  7 +import cn.fw.hermes.domain.enums.AccountTypeEnum
7 8 import cn.fw.hermes.domain.xinge.XinGeProfile
8 9 import cn.fw.hermes.service.biz.XgPushBizService
9 10 import cn.fw.hermes.service.property.XinGeProperty
... ... @@ -13,6 +14,7 @@ import org.springframework.validation.annotation.Validated
13 14 import org.springframework.web.bind.annotation.GetMapping
14 15 import org.springframework.web.bind.annotation.RequestMapping
15 16 import org.springframework.web.bind.annotation.RestController
  17 +import javax.validation.constraints.NotNull
16 18  
17 19 /**
18 20 * 信鸽debug类
... ... @@ -29,8 +31,8 @@ import org.springframework.web.bind.annotation.RestController
29 31 class XinGeDebugController(private val xinGeProperty: XinGeProperty, private val xgPushBizService: XgPushBizService) {
30 32 @ControllerMethod("信鸽推送测试消息")
31 33 @GetMapping("/send/msg")
32   - fun sendMsg(): Message<Void> {
33   - xgPushBizService.sendData()
  34 + fun sendMsg(@NotNull(message = "用户id不能为空") userId: Long?): Message<Void> {
  35 + userId?.let { xgPushBizService.sendData(it, AccountTypeEnum.B_USER) }
34 36 return success()
35 37 }
36 38  
... ...
fw-hermes-service/src/main/java/cn/fw/hermes/service/data/HermesService.java
... ... @@ -15,5 +15,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
15 15 */
16 16 public interface HermesService extends IService<Hermes> {
17 17 Hermes queryByUserId(Long userId, AccountTypeEnum accountTypeEnum);
  18 +
18 19 void saveByDto(HermesDTO dto);
19 20 }
... ...
fw-hermes-service/src/main/java/cn/fw/hermes/service/data/impl/HermesServiceImpl.java
... ... @@ -30,14 +30,14 @@ public class HermesServiceImpl extends ServiceImpl&lt;HermesMapper, Hermes&gt; impleme
30 30 @Override
31 31 public Hermes queryByUserId(Long userId, AccountTypeEnum type) {
32 32 return getOne(Wrappers.<Hermes>lambdaQuery()
33   - .eq(Hermes::getUserId, userId)
34   - .eq(Hermes::getAccountType, type)
35   - , Boolean.FALSE);
  33 + .eq(Hermes::getUserId, userId)
  34 + .eq(Hermes::getAccountType, type)
  35 + , Boolean.FALSE);
36 36 }
37 37  
38 38 @Transactional(rollbackFor = Exception.class)
39 39 @Override
40   - @CacheEvict(cacheNames = Constant.ACCOUNT_CACHE_KEY, key = "#dto.userId", condition = "#dto.id != null")
  40 + @CacheEvict(cacheNames = Constant.ACCOUNT_CACHE_KEY, key = "#dto.userId+':'+#dto.accountType.name()", condition = "#dto.id != null")
41 41 public void saveByDto(HermesDTO dto) {
42 42 Hermes db = new Hermes();
43 43 BeanUtils.copyProperties(dto, db);
... ...
fw-hermes-service/src/main/kotlin/cn/fw/hermes/service/biz/XgPushBizService.kt
1 1 package cn.fw.hermes.service.biz
2 2  
  3 +import cn.fw.common.businessvalidator.Validator.BV
  4 +import cn.fw.common.util.logInfo
  5 +import cn.fw.hermes.common.constant.Constant
  6 +import cn.fw.hermes.domain.db.Hermes
  7 +import cn.fw.hermes.domain.enums.AccountTypeEnum
  8 +import cn.fw.hermes.service.data.HermesService
  9 +import com.baomidou.mybatisplus.core.toolkit.Wrappers
3 10 import com.tencent.xinge.XingeApp
4 11 import com.tencent.xinge.bean.AudienceType
5 12 import com.tencent.xinge.bean.Message
6 13 import com.tencent.xinge.bean.MessageAndroid
7 14 import com.tencent.xinge.bean.MessageType
  15 +import com.tencent.xinge.device.account.AccountBindOperatorType
  16 +import com.tencent.xinge.device.account.AccountBindRequest
  17 +import com.tencent.xinge.device.account.AccountTypePair
  18 +import com.tencent.xinge.device.account.TokenAccountsPair
8 19 import com.tencent.xinge.push.app.PushAppRequest
  20 +import kotlinx.coroutines.CoroutineScope
  21 +import kotlinx.coroutines.Dispatchers
  22 +import kotlinx.coroutines.launch
  23 +import org.springframework.beans.factory.annotation.Value
  24 +import org.springframework.cloud.context.config.annotation.RefreshScope
  25 +import org.springframework.data.redis.core.StringRedisTemplate
9 26 import org.springframework.stereotype.Service
  27 +import org.springframework.transaction.annotation.Transactional
10 28 import java.util.*
11 29  
12 30  
... ... @@ -19,10 +37,49 @@ import java.util.*
19 37 * @date : 2024-01-04 15:54
20 38 */
21 39 @Service
22   -class XgPushBizService(private val xingeApp: XingeApp) {
  40 +@RefreshScope
  41 +class XgPushBizService(
  42 + @Value("\${spring.cache.custom.global-prefix}:xg:token")
  43 + private val keyPrefix: String,
  44 + private val xingeApp: XingeApp,
  45 + private val hermesService: HermesService,
  46 + private val stringRedisTemplate: StringRedisTemplate
  47 +) {
23 48  
  49 + /**
  50 + * 储存和更新用户腾讯信鸽设备的token
  51 + */
  52 + @Transactional(rollbackFor = [Exception::class])
  53 + fun saveUserToken(userId: Long?, accountType: AccountTypeEnum, xgToken: String) {
  54 + BV.notNull(userId) { "用户信息不存在" }
  55 + userId?.let {
  56 + val hermes = hermesService.queryByUserId(it, accountType)
  57 + hermes?.run {
  58 + val cacheKey = "${keyPrefix}:${accountType.name}"
  59 + val hashOps = stringRedisTemplate.boundHashOps<String, String>(cacheKey)
  60 + val clearUserIds = blankingToken(it, accountType, xgToken)
  61 + CoroutineScope(Dispatchers.IO).launch {
  62 + clearTokenAccount(xgToken, identifier)
  63 + }
  64 + val her = Hermes()
  65 + her.id = id
  66 + her.xgToken = xgToken
  67 + if (her.updateById()) {
  68 + hashOps.put(it.toString(), xgToken)
  69 + }
  70 + if (clearUserIds.isNotEmpty()) {
  71 + val clearUserList = clearUserIds.map { userId -> userId.toString() }.toTypedArray()
  72 + hashOps.delete(*clearUserList)
  73 + }
  74 + }
  75 + }
  76 + }
24 77  
25   - fun sendData() {
  78 + fun sendData(userId: Long, accountType: AccountTypeEnum) {
  79 + val xgToken = getUserToken(userId, accountType)
  80 + BV.isFalse(Constant.inValidToken == xgToken) {
  81 + "用户设备未找到"
  82 + }
26 83 val pushAppRequest = PushAppRequest()
27 84 pushAppRequest.audience_type = AudienceType.token
28 85 pushAppRequest.message_type = MessageType.notify
... ... @@ -39,7 +96,47 @@ class XgPushBizService(private val xingeApp: XingeApp) {
39 96 messageAndroid.setnCategory("CATEGORY_REMINDER")
40 97 messageAndroid.ring_raw = "xg_ring"
41 98 message.android = messageAndroid
42   - pushAppRequest.token_list = arrayListOf("02b9c9dc7b4c2c392f08fd793397e4f50571")
  99 + pushAppRequest.token_list = arrayListOf(xgToken)
43 100 this.xingeApp.pushApp(pushAppRequest)
44 101 }
  102 +
  103 + private fun getUserToken(userId: Long, accountType: AccountTypeEnum): String {
  104 + val cacheKey = "${keyPrefix}:${accountType.name}"
  105 + val hashOps = stringRedisTemplate.boundHashOps<String, String>(cacheKey)
  106 + val xToken = hashOps.get(userId.toString())
  107 + return xToken ?: hermesService.queryByUserId(userId, accountType)?.xgToken ?: Constant.inValidToken
  108 + }
  109 +
  110 + private fun clearTokenAccount(token: String, account: String) {
  111 + val request = AccountBindRequest()
  112 + request.operatorType = AccountBindOperatorType.BatchCoverAccount
  113 + val accountTypePair = AccountTypePair()
  114 + accountTypePair.account = account
  115 +
  116 + val accountTypePairs = arrayListOf(accountTypePair)
  117 + request.accountList = accountTypePairs
  118 +
  119 + val tokenAccountsPair = TokenAccountsPair()
  120 + tokenAccountsPair.accountList = accountTypePairs
  121 + tokenAccountsPair.token = token
  122 +
  123 + request.tokenAccounts = arrayListOf(tokenAccountsPair)
  124 + val bindRes = this.xingeApp.accountBind(request)
  125 + logInfo("给[{}]绑定账号[{}], 结果: {}", token, account, bindRes)
  126 + }
  127 +
  128 + private fun blankingToken(userId: Long, accountType: AccountTypeEnum, xgToken: String): List<Long> {
  129 + val list = hermesService.list(
  130 + Wrappers.lambdaQuery<Hermes>()
  131 + .eq(Hermes::getXgToken, xgToken)
  132 + .eq(Hermes::getAccountType, accountType)
  133 + .ne(Hermes::getUserId, userId)
  134 + )
  135 + if (list.isNullOrEmpty()) {
  136 + return listOf()
  137 + }
  138 + list.forEach { it.xgToken = Constant.inValidToken }
  139 + hermesService.updateBatchById(list)
  140 + return list.map(Hermes::getUserId)
  141 + }
45 142 }
... ...