1.首先进行建表
大部分点赞都是文章,帖子,或者商品的收藏,然后登录用户进行收藏,创建表的话需要文章,帖子,或者商品的id和用户的id,我这里是文章postId和ud
2.接下来就是代码层面的实现
ourcontroller层(PostFavAddRequest中放的是文章id)
@PostMapping("/")
public BaseResponse<Integer> doPostFavour(@RequestBody PostFavourAddRequest postFavourAddRequest,
HttpServletRequest request) {
if (postFavourAddRequest == null || postFavourAddRequest.getPostId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
// 登录才能操作
final User loginUser = userService.getLoginUser(request);
long postId = postFavourAddRequest.getPostId();
int result = postFavourService.doPostFavour(postId, loginUser);
return ResultUtils.success(result);
}
service层
int doPostFavour(long postId, User loginUser);
serviceImpl层(用户串行点赞必须加锁)
@Override
public int doPostFavour(long postId, User loginUser) {
// 判断是否存在
Post post = postService.getById(postId);
if (post == null) {
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
}
// 是否已帖子收藏
long userId = loginUser.getId();
// 每个用户串行帖子收藏
// 锁必须要包裹住事务方法
//在同一个类中,非事务方法A调用事务方法B,事务失效,得采用AopContext.currentProxy().xx()来进行调用,事务才能生效。
PostFavourService postFavourService = (PostFavourService) AopContext.currentProxy();
synchronized (String.valueOf(userId).intern()) {
return postFavourService.doPostFavourInner(userId, postId);
}
doPostThumbInner是对数据库进行操作的,实现如下
/**
* 帖子收藏(内部服务)
*
* @param userId
* @param postId
* @return
*/
int doPostFavourInner(long userId, long postId);
封装了事务的方法,出现错误立即回滚。
大概逻辑就是首先判断首先是否已经进行过收藏,如果已经收藏,当用户在进行收藏时,会取消收藏,首先移除收藏表里的信息,如果移除成功,将post里的收藏数进行更新,收藏数必须大于0才能进行减一操作,修改成功返回-1,失败返回0。如果用户未进行收藏更新post里的收藏数,收藏数进行加一操作
@Override
@Transactional(rollbackFor = Exception.class)
public int doPostFavourInner(long userId, long postId) {
PostFavour postFavour = new PostFavour();
postFavour.setUserId(userId);
postFavour.setPostId(postId);
QueryWrapper<PostFavour> postFavourQueryWrapper = new QueryWrapper<>(postFavour);
PostFavour oldPostFavour = this.getOne(postFavourQueryWrapper);
boolean result;
// 已收藏
if (oldPostFavour != null) {
result = this.remove(postFavourQueryWrapper);
if (result) {
// 帖子收藏数 - 1
result = postService.update()
.eq("id", postId)
.gt("favourNum", 0)
.setSql("favourNum = favourNum - 1")
.update();
return result ? -1 : 0;
} else {
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
}
} else {
// 未帖子收藏
result = this.save(postFavour);
if (result) {
// 帖子收藏数 + 1
result = postService.update()
.eq("id", postId)
.setSql("favourNum = favourNum + 1")
.update();
return result ? 1 : 0;
} else {
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
}
}
}
接下来就是如何查看自己的收藏(点赞)的作品,点赞和收藏逻辑一模一样。首先以page的形式展现出来
controller层(当前登录id即为点赞或者收藏的id)
@PostMapping("/my/list/page")
public BaseResponse<Page<PostVO>> listMyFavourPostByPage(@RequestBody PostQueryRequest postQueryRequest,
HttpServletRequest request) {
if (postQueryRequest == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
User loginUser = userService.getLoginUser(request);
long current = postQueryRequest.getCurrent();
long size = postQueryRequest.getPageSize();
// 限制爬虫
ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
Page<Post> postPage = postFavourService.listFavourPostByPage(new Page<>(current, size),
postService.getQueryWrapper(postQueryRequest), loginUser.getId());
return ResultUtils.success(postService.getPostVOPage(postPage, request));
}
getQueryWrapper方法(实际就是拼接sql语句查询)
public QueryWrapper<Post> getQueryWrapper(PostQueryRequest postQueryRequest) {
QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
if (postQueryRequest == null) {
return queryWrapper;
}
String searchText = postQueryRequest.getSearchText();
String sortField = postQueryRequest.getSortField();
String sortOrder = postQueryRequest.getSortOrder();
Long id = postQueryRequest.getId();
String title = postQueryRequest.getTitle();
String content = postQueryRequest.getContent();
List<String> tagList = postQueryRequest.getTags();
Long userId = postQueryRequest.getUserId();
Long notId = postQueryRequest.getNotId();
// 拼接查询条件
if (StringUtils.isNotBlank(searchText)) {
queryWrapper.like("title", searchText).or().like("content", searchText);
}
queryWrapper.like(StringUtils.isNotBlank(title), "title", title);
queryWrapper.like(StringUtils.isNotBlank(content), "content", content);
if (CollectionUtils.isNotEmpty(tagList)) {
for (String tag : tagList) {
queryWrapper.like("tags", "\"" + tag + "\"");
}
}
queryWrapper.ne(ObjectUtils.isNotEmpty(notId), "id", notId);
queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "userId", userId);
queryWrapper.eq("isDelete", false);
queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
sortField);
return queryWrapper;
}
getPostVoPage就是关联查询用户信息以及点赞收藏信息
public Page<PostVO> getPostVOPage(Page<Post> postPage, HttpServletRequest request) {
//获取记录数list集合
List<Post> postList = postPage.getRecords();
//getTotal()获取记录总数,getRecords()是获取记录数,getCurrent()获取当前页数,getPages()获取总页数
Page<PostVO> postVOPage = new Page<>(postPage.getCurrent(), postPage.getSize(), postPage.getTotal());
if (CollectionUtils.isEmpty(postList)) {
return postVOPage;
}
// 1. 关联查询用户信息
//以userid作为键返回的set集合
Set<Long> userIdSet = postList.stream().map(Post::getUserId).collect(Collectors.toSet());
//将set集合转换为map键为集合
Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
.collect(Collectors.groupingBy(User::getId));
// 2. 已登录,获取用户点赞、收藏状态
Map<Long, Boolean> postIdHasThumbMap = new HashMap<>();
Map<Long, Boolean> postIdHasFavourMap = new HashMap<>();
//获得当前登录用户
User loginUser = userService.getLoginUserPermitNull(request);
if (loginUser != null) {
Set<Long> postIdSet = postList.stream().map(Post::getId).collect(Collectors.toSet());
loginUser = userService.getLoginUser(request);
// 获取点赞
QueryWrapper<PostThumb> postThumbQueryWrapper = new QueryWrapper<>();
postThumbQueryWrapper.in("postId", postIdSet);
postThumbQueryWrapper.eq("userId", loginUser.getId());
//获取点赞列表
List<PostThumb> postPostThumbList = postThumbMapper.selectList(postThumbQueryWrapper);
postPostThumbList.forEach(postPostThumb -> postIdHasThumbMap.put(postPostThumb.getPostId(), true));
// 获取收藏
QueryWrapper<PostFavour> postFavourQueryWrapper = new QueryWrapper<>();
postFavourQueryWrapper.in("postId", postIdSet);
postFavourQueryWrapper.eq("userId", loginUser.getId());
List<PostFavour> postFavourList = postFavourMapper.selectList(postFavourQueryWrapper);
postFavourList.forEach(postFavour -> postIdHasFavourMap.put(postFavour.getPostId(), true));
}
// 填充信息
List<PostVO> postVOList = postList.stream().map(post -> {
//将字符串转换为json格式
PostVO postVO = PostVO.objToVo(post);
Long userId = post.getUserId();
User user = null;
if (userIdUserListMap.containsKey(userId)) {
user = userIdUserListMap.get(userId).get(0);
}
//设置脱敏后的user设置点赞数和收藏数
postVO.setUser(userService.getUserVO(user));
//这两个Map是基于postId作为key,psot的信息作为值,在这里根据postId来获取post的值
postVO.setHasThumb(postIdHasThumbMap.getOrDefault(post.getId(), false));
postVO.setHasFavour(postIdHasFavourMap.getOrDefault(post.getId(), false));
return postVO;
}).collect(Collectors.toList());
postVOPage.setRecords(postVOList);
return postVOPage;
}
objToVo方法(将post中的json类型Tags转换为字符串)
public static PostVO objToVo(Post post) {
if (post == null) {
return null;
}
PostVO postVO = new PostVO();
BeanUtils.copyProperties(post, postVO);
//将字符串型的tags转换为json格式
postVO.setTagList(GSON.fromJson(post.getTags(), new TypeToken<List<String>>() {
}.getType()));
return postVO;
}
service层
Page<Post> listFavourPostByPage(IPage<Post> page, Wrapper<Post> queryWrapper,
long favourUserId);
serviceimpl层
@Override
public Page<Post> listFavourPostByPage(IPage<Post> page, Wrapper<Post> queryWrapper, long favourUserId) {
if (favourUserId <= 0) {
return new Page<>();
}
return baseMapper.listFavourPostByPage(page, queryWrapper, favourUserId);
}
MyBatis-Plus 最核心的功能要数通用 Mapper 了,只要我们的 Mapper 接口实现了 BaseMapper,就可以完成单表大部分的 CRUD 操作了,并且它还附带了一个功能强大的条件构造器。
所以此处的baseMapper就是底层mapper,创建了listFavourPostByPage这个方法
在PostFavourMapper中
Page<Post> listFavourPostByPage(IPage<Post> page, @Param(Constants.WRAPPER) Wrapper<Post> queryWrapper,
long favourUserId);
.xml中(对于这样父子查询的sql,首先先执行子sql,然后再执行父sql,对于这个sql,首先查询postId,然后再进行关联查询)
important(关联查询到文章)
<select id="listFavourPostByPage" resultType="文件路径">
select p.*
from post p
join (select postId from post_favour where userId = #{favourUserId}) pf
on p.id = pf.postId ${ew.customSqlSegment}
</select>
到此为止,就可以获得自己收藏或者点赞的文章了!!