一、发布探店笔记
1.1 简介
探店笔记类似点评网站的评价,往往是图文结合。点击首页最下方菜单栏中的+按钮,即可发布探店图文:
文件上传的设置如下:
1.2 需求描述
点击首页的探店笔记,会进入详情页面,实现该页面的查询接口:
1.3 代码实现
对应的 controller 层代码如下:
RestController
@RequestMapping("/blog")
public class BlogController {
@Resource
private IBlogService blogService;
@GetMapping("/{id}")
public Result queryBlogById(@PathVariable("id") Long id){
return blogService.queryBlogById(id);
}
}
对应的 service 层代码如下:
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
@Resource
private IUserService userService;
@Override
public Result queryBlogById(Long id) {
// 1、查询 blog
Blog blog = getById(id);
if(blog == null){
return Result.fail("笔记不存在");
}
// 2、查询 blog 相关的用户
queryBlogUser(blog);
return Result.ok(blog);
}
public void queryBlogUser(Blog blog){
Long userId = blog.getUserId();
User user = userService.getById(userId);
blog.setName(user.getNickName());
blog.setIcon(user.getIcon());
}
}
二、点赞
2.1 简介
在首页的探店笔记排行榜和探店图文详情页面都有点赞的功能:如下图,当点击点赞按钮的时候,就会向后端发送一个请求,请求的地址也在下图上,其中 url 最后是笔记的 id,
2.2 需求描述
同一个用户只能点赞一次,再次点击则取消点赞;如果当前用户已经点赞,则点赞按钮高亮显示(前端已实现,判断字段 Blog 类的 isLike 属性即可)。
2.3 实现步骤
1、给 Blog 类中添加一个 isLike 字段,标示是否被当前用户点赞
2、修改点赞功能,利用 Redis 的 set 集合判断是否点赞过,未点赞过则点赞数 +1,已点赞过则点赞数 -1
3、修改根据 id 查询 Blog 的业务,判断当前登录用户是否点赞过,赋值给 isLike 字段
4、修改分页查询 Blog 业务,判断当前登录用户是否点赞过,赋值给 isLike 字段
2.4 代码实现
对应的 controller 层代码如下:
RestController
@RequestMapping("/blog")
public class BlogController {
@Resource
private IBlogService blogService;
@GetMapping("/{id}")
public Result queryBlogById(@PathVariable("id") Long id){
return blogService.queryBlogById(id);
}
@GetMapping("/{id}")
public Result queryBlogById(@PathVariable("id") Long id){
return blogService.queryBlogById(id);
}
}
对应的 services 层代码如下:
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
@Resource
private IUserService userService;
@Resource
StringRedisTemplate stringRedisTemplate;
@Override
public Result queryHotBlog(Integer current) {
// 根据用户查询
Page<Blog> page = query()
.orderByDesc("liked")
.page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
// 获取当前页数据
List<Blog> records = page.getRecords();
// 查询用户
records.forEach(blog -> {
queryBlogUser(blog);
// 查询 blog 是否被点赞
isBlogLiked(blog);
});
return Result.ok(records);
}
private void isBlogLiked(Blog blog){
// 1、获取当前用户
UserDTO user = UserHolder.getUser();
String key = "blog:liked:"+blog.getId();
// 2、判断当前用户是否已经点赞了
Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, user.getId().toString());
blog.setIsLike(BooleanUtil.isTrue(isMember));
}
@Override
public Result likeBlog(Long id) {
// 1、获取当前用户
UserDTO user = UserHolder.getUser();
String key = "blog:liked:"+id;
// 2、判断当前用户是否已经点赞了
Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, user.getId().toString());
// 3、如果没有点赞,可以点赞
if(BooleanUtil.isFalse(isMember)){
// 3.1 数据库点赞数 +1
boolean success = update().setSql("liked = liked + 1").eq("id", id).update();
if(success){
// 3.2 保存用户到 redis 的 set 集合
stringRedisTemplate.opsForSet().add(key,userId.toString());
}
}else{
// 4、如果点赞了,取消点赞
// 4.1 数据库点赞数 -1
boolean success = update().setSql("liked = liked - 1").eq("id", id).update();
if(success){
// 4.2 保存用户到 redis 的 set 集合
stringRedisTemplate.opsForSet().remove(key,userId.toString());
}
}
return Result.ok();
}
@Override
public Result queryBlogById(Long id) {
// 1、查询 blog
Blog blog = getById(id);
if(blog == null){
return Result.fail("笔记不存在");
}
// 2、查询 blog 相关的用户
queryBlogUser(blog);
isBlogLiked(blog);
return Result.ok(blog);
}
public void queryBlogUser(Blog blog){
Long userId = blog.getUserId();
User user = userService.getById(userId);
blog.setName(user.getNickName());
blog.setIcon(user.getIcon());
}
}
三、 点赞排行榜
3.1 简介
在探店笔记的详情页面,应该把给该笔记点赞的人显示出来,比如最早点赞的 TOP5,形成点赞排行榜:
3.2 需求描述
按照点赞时间先后排序,返回 Top5 的用户,我们实现点赞功能使用的是 redis 的 set 类型,在这里就不行了,因为 set 不支持排序功能,这里我们需要使用 zset 类型,因为此种类型才有排序、不重复等特点。
3.3 代码实现
对应的 controller 层代码如下:
RestController
@RequestMapping("/blog")
public class BlogController {
@Resource
private IBlogService blogService;
@GetMapping("/{id}")
public Result queryBlogById(@PathVariable("id") Long id){
return blogService.queryBlogById(id);
}
@GetMapping("/{id}")
public Result queryBlogById(@PathVariable("id") Long id){
return blogService.queryBlogById(id);
}
@GetMapping("/likes/{id}")
public Result queryBlogLikes(@PathVariable("id") Long id){
return blogService.queryBlogLikes(id);
}
}
对应的 services 层代码如下:
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
@Resource
private IUserService userService;
@Resource
StringRedisTemplate stringRedisTemplate;
@Override
public Result queryHotBlog(Integer current) {
// 根据用户查询
Page<Blog> page = query()
.orderByDesc("liked")
.page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
// 获取当前页数据
List<Blog> records = page.getRecords();
// 查询用户
records.forEach(blog -> {
queryBlogUser(blog);
// 查询 blog 是否被点赞
isBlogLiked(blog);
});
return Result.ok(records);
}
private void isBlogLiked(Blog blog){
// 1、获取当前用户
UserDTO user = UserHolder.getUser();
if(user == null){
// 用户未登录
return ;
}
String key = "blog:liked:"+blog.getId();
// 2、判断当前用户是否已经点赞了
Double score = stringRedisTemplate.opsForZSet().score(key, user.getId().toString());
blog.setIsLike(score != null);
}
@Override
public Result likeBlog(Long id) {
// 1、获取当前用户
UserDTO user = UserHolder.getUser();
String key = "blog:liked:"+id;
// 2、判断当前用户是否已经点赞了
Double score = stringRedisTemplate.opsForZSet().score(key, user.getId().toString());
// 3、如果没有点赞,可以点赞
if(score == null){
// 3.1 数据库点赞数 +1
boolean success = update().setSql("liked = liked + 1").eq("id", id).update();
if(success){
// 3.2 保存用户到 redis 的 set 集合 zadd key value score
stringRedisTemplate.opsForZSet().add(key,user.getId().toString(),System.currentTimeMillis());
}
}else{
// 4、如果点赞了,取消点赞
// 4.1 数据库点赞数 -1
boolean success = update().setSql("liked = liked - 1").eq("id", id).update();
if(success){
// 4.2 保存用户到 redis 的 set 集合
stringRedisTemplate.opsForZSet().remove(key,user.getId().toString());
}
}
return Result.ok();
}
@Override
public Result queryBlogLikes(Long id) {
// 查找 top5 的点赞用户
String key = "blog:liked:"+id;
Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4);
if(top5 == null || top5.isEmpty()){
return Result.ok(Collections.emptyList());
}
// 2、解析其中的用户 id
List<Long> ids = top5.stream().map(userId -> Long.valueOf(userId)).collect(Collectors.toList());
String idStr = StrUtil.join(",", ids);
// 3、根据用户id 查询用户
List<UserDTO> userDTOS = userService.query().in("id", ids)
.last("order by field(id," + idStr + ")").list()
.stream()
.map(user -> BeanUtil.copyProperties(user, UserDTO.class))
.collect(Collectors.toList());
// 4、返回
return Result.ok(userDTOS);
}
@Override
public Result queryBlogById(Long id) {
// 1、查询 blog
Blog blog = getById(id);
if(blog == null){
return Result.fail("笔记不存在");
}
// 2、查询 blog 相关的用户
queryBlogUser(blog);
isBlogLiked(blog);
return Result.ok(blog);
}
public void queryBlogUser(Blog blog){
Long userId = blog.getUserId();
User user = userService.getById(userId);
blog.setName(user.getNickName());
blog.setIcon(user.getIcon());
}
}