mp:实现 tag 模块的后端接口

pull/2/head
YunaiV 2023-01-08 11:29:44 +08:00
parent acee075260
commit d1cc9dde0c
11 changed files with 215 additions and 13 deletions

View File

@ -14,12 +14,19 @@ public interface ErrorCodeConstants {
ErrorCode ACCOUNT_GENERATE_QR_CODE_FAIL = new ErrorCode(1006000001, "生成公众号二维码失败,原因:{}");
ErrorCode ACCOUNT_CLEAR_QUOTA_FAIL = new ErrorCode(1006000001, "清空公众号的 API 配额失败,原因:{}");
// ========== 公众号账号 1006001000============
// ========== 公众号统计 1006001000============
ErrorCode STATISTICS_GET_USER_SUMMARY_FAIL = new ErrorCode(1006001000, "获取用户增减数据失败,原因:{}");
ErrorCode STATISTICS_GET_USER_CUMULATE_FAIL = new ErrorCode(1006001001, "获得用户累计数据失败,原因:{}");
ErrorCode STATISTICS_GET_UPSTREAM_MESSAGE_FAIL = new ErrorCode(1006001002, "获得消息发送概况数据失败,原因:{}");
ErrorCode STATISTICS_GET_INTERFACE_SUMMARY_FAIL = new ErrorCode(1006001003, "获得接口分析数据失败,原因:{}");
// ========== 公众号标签 1006002000============
ErrorCode TAG_NOT_EXISTS = new ErrorCode(1006002000, "标签不存在");
ErrorCode TAG_CREATE_FAIL = new ErrorCode(1006002001, "创建标签失败,原因:{}");
ErrorCode TAG_UPDATE_FAIL = new ErrorCode(1006002001, "更新标签失败,原因:{}");
ErrorCode TAG_DELETE_FAIL = new ErrorCode(1006002001, "删除标签失败,原因:{}");
ErrorCode TAG_GET_FAIL = new ErrorCode(1006002001, "获得标签失败,原因:{}");
// TODO 要处理下
ErrorCode COMMON_NOT_EXISTS = new ErrorCode(1006001002, "用户不存在");

View File

@ -1,4 +1,4 @@
### 请求 /login 接口 => 成功
### 请求 /mp/menu/save 接口 => 成功
POST {{baseUrl}}/mp/menu/save
Content-Type: application/json
Authorization: Bearer {{token}}

View File

@ -0,0 +1,39 @@
### 请求 /mp/tag/create 接口 => 成功
POST {{baseUrl}}/mp/tag/create
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"accountId": "1",
"name": "测试"
}
### 请求 /mp/tag/update 接口 => 成功
PUT {{baseUrl}}/mp/tag/update
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"id": "3",
"name": "测试标签啦"
}
### 请求 /mp/tag/delete 接口 => 成功
DELETE {{baseUrl}}/mp/tag/delete?id=3
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /mp/tag/page 接口 => 成功
GET {{baseUrl}}/mp/tag/page?accountId=1&pageNo=1&pageSize=10
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /mp/tag/sync 接口 => 成功
POST {{baseUrl}}/mp/tag/sync?accountId=1
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@ -62,4 +62,13 @@ public class MpTagController {
return success(MpTagConvert.INSTANCE.convertPage(pageResult));
}
@PostMapping("/sync")
@ApiOperation("同步公众标签")
@ApiImplicitParam(name = "id", value = "公众号账号的编号", required = true, dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('mp:tag:sync')")
public CommonResult<Boolean> syncTag(@RequestParam("accountId") Long accountId) {
mpTagService.syncTag(accountId);
return success(true);
}
}

View File

@ -6,7 +6,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
import java.util.Date;
@ApiModel("管理后台 - 公众号标签 Response VO")
@ -15,10 +14,12 @@ import java.util.Date;
@ToString(callSuper = true)
public class MpTagRespVO extends MpTagBaseVO {
@ApiModelProperty(value = "编号", required = true)
@NotNull(message = "编号不能为空")
@ApiModelProperty(value = "编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "此标签下粉丝数量", required = true, example = "0")
private Integer count;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;

View File

@ -1,12 +1,14 @@
package cn.iocoder.yudao.module.mp.convert.tag;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagCreateReqVO;
import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagRespVO;
import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagUpdateReqVO;
import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
import cn.iocoder.yudao.module.mp.dal.dataobject.tag.MpTagDO;
import me.chanjar.weixin.mp.bean.tag.WxUserTag;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@ -16,8 +18,6 @@ public interface MpTagConvert {
MpTagConvert INSTANCE = Mappers.getMapper(MpTagConvert.class);
WxUserTag convert(MpTagCreateReqVO bean);
WxUserTag convert(MpTagUpdateReqVO bean);
MpTagRespVO convert(WxUserTag bean);
@ -26,4 +26,14 @@ public interface MpTagConvert {
PageResult<MpTagRespVO> convertPage(PageResult<MpTagDO> page);
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(source = "tag.id", target = "tagId"),
@Mapping(source = "tag.name", target = "name"),
@Mapping(source = "tag.count", target = "count"),
@Mapping(source = "account.id", target = "accountId"),
@Mapping(source = "account.appId", target = "appId"),
})
MpTagDO convert(WxUserTag tag, MpAccountDO account);
}

View File

@ -5,6 +5,7 @@ import lombok.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import me.chanjar.weixin.mp.bean.tag.WxUserTag;
/**
* DO
@ -31,6 +32,12 @@ public class MpTagDO extends BaseDO {
*
*/
private String name;
/**
*
*
* {@link WxUserTag#getCount()}
*/
private Integer count;
/**
* ID

View File

@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagPageReqVO;
import cn.iocoder.yudao.module.mp.dal.dataobject.tag.MpTagDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface MpTagMapper extends BaseMapperX<MpTagDO> {
@ -17,4 +19,8 @@ public interface MpTagMapper extends BaseMapperX<MpTagDO> {
.orderByDesc(MpTagDO::getId));
}
default List<MpTagDO> selectListByAccountId(Long accountId) {
return selectList(MpTagDO::getAccountId, accountId);
}
}

View File

@ -9,6 +9,9 @@ import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.ACCOUNT_NOT_EXISTS;
/**
* Service
*
@ -51,6 +54,20 @@ public interface MpAccountService {
*/
MpAccountDO getAccount(Long id);
/**
*
*
* @param id
* @return
*/
default MpAccountDO getRequiredAccount(Long id) {
MpAccountDO account = getAccount(id);
if (account == null) {
throw exception(ACCOUNT_NOT_EXISTS);
}
return account;
}
/**
*
*

View File

@ -45,4 +45,11 @@ public interface MpTagService {
*/
PageResult<MpTagDO> getTagPage(MpTagPageReqVO pageReqVO);
/**
*
*
* @param accountId
*/
void syncTag(Long accountId);
}

View File

@ -1,18 +1,33 @@
package cn.iocoder.yudao.module.mp.service.tag;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagCreateReqVO;
import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagPageReqVO;
import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagUpdateReqVO;
import cn.iocoder.yudao.module.mp.convert.tag.MpTagConvert;
import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
import cn.iocoder.yudao.module.mp.dal.dataobject.tag.MpTagDO;
import cn.iocoder.yudao.module.mp.dal.mysql.tag.MpTagMapper;
import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.tag.WxUserTag;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*;
/**
* Service
@ -27,29 +42,113 @@ public class MpTagServiceImpl implements MpTagService {
@Resource
private MpTagMapper mpTagMapper;
@Resource
private MpAccountService mpAccountService;
@Resource
@Lazy // 延迟加载,为了解决延迟加载
private MpServiceFactory mpServiceFactory;
@Override
public Long createTag(MpTagCreateReqVO createReqVO) {
// return wxMpService.getUserTagService().tagCreate(createReqVO.getName());
return null;
// 获得公众号账号
MpAccountDO account = mpAccountService.getRequiredAccount(createReqVO.getAccountId());
// 第一步,新增标签到公众号平台。标签名的唯一,交给公众号平台
WxMpService mpService = mpServiceFactory.getRequiredMpService(createReqVO.getAccountId());
WxUserTag wxTag;
try {
wxTag = mpService.getUserTagService().tagCreate(createReqVO.getName());
} catch (WxErrorException e) {
throw exception(TAG_CREATE_FAIL, e.getError().getErrorMsg());
}
// 第二步,新增标签到数据库
MpTagDO tag = MpTagConvert.INSTANCE.convert(wxTag, account);
mpTagMapper.insert(tag);
return tag.getId();
}
@Override
public void updateTag(MpTagUpdateReqVO updateReqVO) {
// return wxMpService.getUserTagService().tagUpdate(updateReqVO.getId(), updateReqVO.getName());
// 校验标签存在
MpTagDO tag = validateTagExists(updateReqVO.getId());
// 第一步,更新标签到公众号平台。标签名的唯一,交给公众号平台
WxMpService mpService = mpServiceFactory.getRequiredMpService(tag.getAccountId());
try {
mpService.getUserTagService().tagUpdate(tag.getTagId(), updateReqVO.getName());
} catch (WxErrorException e) {
throw exception(TAG_UPDATE_FAIL, e.getError().getErrorMsg());
}
// 第二步,更新标签到数据库
mpTagMapper.updateById(new MpTagDO().setId(tag.getId()).setName(updateReqVO.getName()));
}
@Override
public void deleteTag(Long id) {
// return wxMpService.getUserTagService().tagDelete(id);
// 校验标签存在
MpTagDO tag = validateTagExists(id);
// 第一步,删除标签到公众号平台。
WxMpService mpService = mpServiceFactory.getRequiredMpService(tag.getAccountId());
try {
mpService.getUserTagService().tagDelete(tag.getTagId());
} catch (WxErrorException e) {
throw exception(TAG_DELETE_FAIL, e.getError().getErrorMsg());
}
// 第二步,删除标签到数据库
mpTagMapper.deleteById(tag.getId());
}
private MpTagDO validateTagExists(Long id) {
MpTagDO tag = mpTagMapper.selectById(id);
if (tag == null) {
throw exception(TAG_NOT_EXISTS);
}
return tag;
}
@Override
public PageResult<MpTagDO> getTagPage(MpTagPageReqVO pageReqVO) {
return null;
return mpTagMapper.selectPage(pageReqVO);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void syncTag(Long accountId) {
MpAccountDO account = mpAccountService.getRequiredAccount(accountId);
// 第一步,从公众号平台获取最新的标签列表
WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId);
List<WxUserTag> wxTags;
try {
wxTags = mpService.getUserTagService().tagGet();
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
// 第二步,合并更新回自己的数据库;由于标签只有 100 个,所以直接 for 循环操作
Map<Long, MpTagDO> tagMap = convertMap(mpTagMapper.selectListByAccountId(accountId),
MpTagDO::getTagId);
wxTags.forEach(wxTag -> {
MpTagDO tag = tagMap.remove(wxTag.getId());
// 情况一,不存在,新增
if (tag == null) {
tag = MpTagConvert.INSTANCE.convert(wxTag, account);
mpTagMapper.insert(tag);
return;
}
// 情况二,存在,则更新
mpTagMapper.updateById(new MpTagDO().setId(tag.getId())
.setName(wxTag.getName()).setCount(wxTag.getCount()));
});
// 情况三,部分标签已经不存在了,删除
if (CollUtil.isNotEmpty(tagMap)) {
mpTagMapper.deleteBatchIds(convertList(tagMap.values(), MpTagDO::getId));
}
}
}