9.5 KiB
9.5 KiB
title, url, publishedTime
| title | url | publishedTime |
|---|---|---|
| 笔记置顶/取消置顶接口开发 - 犬小哈专栏 | https://www.quanxiaoha.com/column/10357.html | null |
本小节中,我们将把笔记置顶、取消置顶接口开发完成,注意,这个接口同时支持置顶与取消置顶操作。
接口定义
接口地址
POST /note/top
入参
{
"id": 1829410872473157676, // 笔记 ID
"isTop": true // 是否置顶,true 表示置顶操作,false 表示取消置顶操作
}
出参
{
"success": true, // true 表示更新成功
"message": null,
"errorCode": null,
"data": null
}
创建接口入参 VO
编辑 xiaohashu-note-biz 模块,在 /model/vo 包下,新增 TopNoteReqVO 入参实体类,代码如下:
package com.quanxiaoha.xiaohashu.note.biz.model.vo;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author: 犬小哈
* @date: 2024/4/7 15:17
* @version: v1.0.0
* @description: 笔记置顶/取消置顶
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TopNoteReqVO {
@NotNull(message = "笔记 ID 不能为空")
private Long id;
@NotNull(message = "置顶状态不能为空")
private Boolean isTop;
}
新增 mapper 更新方法
接着,编辑 NoteDOMapper 接口,添加一个更新笔记置顶状态的方法,代码如下:
package com.quanxiaoha.xiaohashu.note.biz.domain.mapper;
import com.quanxiaoha.xiaohashu.note.biz.domain.dataobject.NoteDO;
public interface NoteDOMapper {
// 省略...
int updateIsTop(NoteDO noteDO);
}
在接口对应的 xml 映射文件中,添加更新 SQL 语句,代码如下:
<update id="updateIsTop" parameterType="com.quanxiaoha.xiaohashu.note.biz.domain.dataobject.NoteDO">
update t_note
set is_top = #{isTop,jdbcType=BIT},
update_time = #{updateTime,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=BIGINT} and creator_id = #{creatorId,jdbcType=BIGINT}
</update>
Tip
: 更新条件中,除了需要传入笔记 ID, 还需要传入笔记的发布者 ID, 用于判断当前登录的用户,是否和发布者是同一个人,只有笔记的作者才能置顶、取消置顶自己的笔记。
添加异常码枚举值
编辑 ResponseCodeEnum 全局枚举类,添加一个您无法操作该笔记的异常码枚举值,业务层判断需要用到:
package com.quanxiaoha.xiaohashu.note.biz.enums;
import com.quanxiaoha.framework.common.exception.BaseExceptionInterface;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author: 犬小哈
* @url: www.quanxiaoha.com
* @date: 2023-08-15 10:33
* @description: 响应异常码
**/
@Getter
@AllArgsConstructor
public enum ResponseCodeEnum implements BaseExceptionInterface {
// 省略...
// ----------- 业务异常状态码 -----------
// 省略...
NOTE_CANT_OPERATE("NOTE-20007", "您无法操作该笔记"),
;
// 省略...
}
编辑 service 业务层
在 NoteService 笔记业务层接口中,声明一个笔记置顶 / 取消置顶方法,代码如下:
package com.quanxiaoha.xiaohashu.note.biz.service;
import com.quanxiaoha.framework.common.response.Response;
import com.quanxiaoha.xiaohashu.note.biz.model.vo.*;
/**
* @author: 犬小哈
* @date: 2024/4/7 15:41
* @version: v1.0.0
* @description: 笔记业务
**/
public interface NoteService {
// 省略...
/**
* 笔记置顶 / 取消置顶
* @param topNoteReqVO
* @return
*/
Response<?> topNote(TopNoteReqVO topNoteReqVO);
}
在其实现类中,实现上述方法,代码如下:
package com.quanxiaoha.xiaohashu.note.biz.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.base.Preconditions;
import com.quanxiaoha.framework.biz.context.holder.LoginUserContextHolder;
import com.quanxiaoha.framework.common.exception.BizException;
import com.quanxiaoha.framework.common.response.Response;
import com.quanxiaoha.framework.common.util.JsonUtils;
import com.quanxiaoha.xiaohashu.note.biz.constant.MQConstants;
import com.quanxiaoha.xiaohashu.note.biz.constant.RedisKeyConstants;
import com.quanxiaoha.xiaohashu.note.biz.domain.dataobject.NoteDO;
import com.quanxiaoha.xiaohashu.note.biz.domain.mapper.NoteDOMapper;
import com.quanxiaoha.xiaohashu.note.biz.domain.mapper.TopicDOMapper;
import com.quanxiaoha.xiaohashu.note.biz.enums.NoteStatusEnum;
import com.quanxiaoha.xiaohashu.note.biz.enums.NoteTypeEnum;
import com.quanxiaoha.xiaohashu.note.biz.enums.NoteVisibleEnum;
import com.quanxiaoha.xiaohashu.note.biz.enums.ResponseCodeEnum;
import com.quanxiaoha.xiaohashu.note.biz.model.vo.*;
import com.quanxiaoha.xiaohashu.note.biz.rpc.DistributedIdGeneratorRpcService;
import com.quanxiaoha.xiaohashu.note.biz.rpc.KeyValueRpcService;
import com.quanxiaoha.xiaohashu.note.biz.rpc.UserRpcService;
import com.quanxiaoha.xiaohashu.note.biz.service.NoteService;
import com.quanxiaoha.xiaohashu.user.dto.resp.FindUserByIdRspDTO;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* @author: 犬小哈
* @date: 2024/4/7 15:41
* @version: v1.0.0
* @description: 笔记业务
**/
@Service
@Slf4j
public class NoteServiceImpl implements NoteService {
// 省略...
/**
* 笔记置顶 / 取消置顶
*
* @param topNoteReqVO
* @return
*/
@Override
public Response<?> topNote(TopNoteReqVO topNoteReqVO) {
// 笔记 ID
Long noteId = topNoteReqVO.getId();
// 是否置顶
Boolean isTop = topNoteReqVO.getIsTop();
// 当前登录用户 ID
Long currUserId = LoginUserContextHolder.getUserId();
// 构建置顶/取消置顶 DO 实体类
NoteDO noteDO = NoteDO.builder()
.id(noteId)
.isTop(isTop)
.updateTime(LocalDateTime.now())
.creatorId(currUserId) // 只有笔记所有者,才能置顶/取消置顶笔记
.build();
int count = noteDOMapper.updateIsTop(noteDO);
if (count == 0) {
throw new BizException(ResponseCodeEnum.NOTE_CANT_OPERATE);
}
// 删除 Redis 缓存
String noteDetailRedisKey = RedisKeyConstants.buildNoteDetailKey(noteId);
redisTemplate.delete(noteDetailRedisKey);
// 同步发送广播模式 MQ,将所有实例中的本地缓存都删除掉
rocketMQTemplate.syncSend(MQConstants.TOPIC_DELETE_NOTE_LOCAL_CACHE, noteId);
log.info("====> MQ:删除笔记本地缓存发送成功...");
return Response.success();
}
// 省略...
}
解释一波业务逻辑:
- 获取入参传过来的笔记 ID, 操作标识,以及从上下文中获取当前登录用户的 ID;
- 构建置顶/取消置顶 DO 实体类;
- 执行更新语句;
- 判断影响的行数,若为 0, 说明当前笔记不允许被操作;
- 否则,删除 Redis 缓存,并同步发送广播模式 MQ,将本地缓存也删除;
新增 controller 接口
最后,编辑 NoteController 控制器,添加 /note/top 接口,代码如下:
package com.quanxiaoha.xiaohashu.note.biz.controller;
import com.quanxiaoha.framework.biz.operationlog.aspect.ApiOperationLog;
import com.quanxiaoha.framework.common.response.Response;
import com.quanxiaoha.xiaohashu.note.biz.model.vo.*;
import com.quanxiaoha.xiaohashu.note.biz.service.NoteService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: 犬小哈
* @date: 2024/4/4 13:22
* @version: v1.0.0
* @description: 笔记
**/
@RestController
@RequestMapping("/note")
@Slf4j
public class NoteController {
// 省略...
@PostMapping(value = "/top")
@ApiOperationLog(description = "置顶/取消置顶笔记")
public Response<?> topNote(@Validated @RequestBody TopNoteReqVO topNoteReqVO) {
return noteService.topNote(topNoteReqVO);
}
}
自测一波
重启笔记服务,自测一下接口功能是否正常,如下图所示:
服务端响应成功,同时,别忘了确认一下数据库中的笔记数据是否更新成功,以及二级缓存是否被删除。