黑马点评-达人探店

发布探店笔记功能

上传照片和发布笔记是两个不相关的功能

上传照片的功能

@Slf4j
@RestController
@RequestMapping("upload")
public class UploadController {

    @PostMapping("blog")
    public Result uploadImage(@RequestParam("file") MultipartFile image) {
        try {
            // 获取原始文件名称
            String originalFilename = image.getOriginalFilename();
            // 生成新文件名
            String fileName = createNewFileName(originalFilename);
            // 保存文件
            image.transferTo(new File(SystemConstants.IMAGE_UPLOAD_DIR, fileName));
            // 返回结果
            log.debug("文件上传成功,{}", fileName);
            return Result.ok(fileName);
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败", e);
        }
    }

发布文章功能

@PostMapping
    public Result saveBlog(@RequestBody Blog blog) {
        //获取登录用户
        UserDTO user = UserHolder.getUser();
        blog.getUserId(user.getId());
        //保存探店文章
        blogService.save(blog);
        //返回id
        return Result.ok(blog.getId());
    }

查询探店笔记

分析页面请求可以发现,是一个get请求,请求路径是/blog/{id},请求的返回值包含笔记信息和相应用户信息,用户信息包括用户头像姓名he

首先查询探店笔记会显示发布人的头像、用户名称以及记录用户ID内容,如何关联笔记与用户?
我们在blog的实体类中加入两个字段,icon和name用于维护用户头像和姓名,其中@TableField(exist = false)表示这个字段不属于数据库中的字段,是需要手动维护的

 /**
     * 用户图标
     */
    @TableField(exist = false)
    private String icon;
    /**
     * 用户姓名
     */
    @TableField(exist = false)
    private String name;

Controller层

@GetMapping("/{id}")
    public Result queryBlogById(@PathVariable("id") Long id) {
        return blogService.queryBlogById(id);
    }

 service层

public interface IBlogService extends IService<Blog> {
    Result queryBlogById(Long id);
}

serviceimpl层

    @Override
    public Result queryBlogById(Long id) {
        // 1.查询blog
        Blog blog = getById(id);
        if (blog == null) {
            return Result.fail("笔记不存在!");
        }
        // 2.查询blog有关的用户
        queryBlogUser(blog);
        // 3.查询blog是否被点赞
        isBlogLiked(blog);
        return Result.ok(blog);
    }
    //用于封装查询到的用户id、头像、名称
    private void queryBlogUser(Blog blog) {
        Long userId = blog.getUserId();
        User user = userService.getById(userId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }

点赞功能

分析一下需求,首先如何判用户有没有点赞,又如何控制isLike字段高亮显示,核心逻辑就一个判断一个用的是否点赞

而点赞的肯定不止一个人,如果单独创建一个数据库表存储点赞人的userId,也能实现,但维护起来复杂,且还要维持数据库中userid不重复。那redis中有没有数据结构即满足可以记录一长串userid,还能满足不重复?--Set集合

先去blog实体类中实现isLike字段,用于记录该笔记是否被点赞

@TableField(exist = false)
private Boolean isLike;
    @Resource
    private StringRedisTemplate stringRedisTemplate;    
    @Override
    public Result likeBlog(Long id) {
        // 1.获取登录用户
        Long userId = UserHolder.getUser().getId();
        // 2.判断当前登录用户是否已经点赞,key是为了标记redis中的内容
        String key = BLOG_LIKED_KEY + id;
        Boolean ismember= stringRedisTemplate.opsForSet().score(key, userId.toString());
        if (BooleanUtil.idfalse(ismember)) {
            // 3.如果未点赞,可以点赞
            // 3.1.数据库点赞数 + 1
            boolean isSuccess = update().setSql("liked = liked + 1").eq("id", id).update();
            // 3.2.保存用户到Redis的set集合  add key value score
            if (isSuccess) {
                stringRedisTemplate.opsForSet().add(key, userId.toString());
            }
        } else {
            // 4.如果已点赞,取消点赞
            // 4.1.数据库点赞数 -1
            boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();
            // 4.2.把用户从Redis的set集合移除
            if (isSuccess) {
                stringRedisTemplate.opsForSet().remove(key, userId.toString());
            }
        }
        return Result.ok();
    }

在完成笔记的点赞功能后,还需要再查询页面显示其他的笔记是否被点赞

private void isBlogLiked(Blog blog) {
        // 1.获取登录用户
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            // 用户未登录,无需查询是否点赞
            return;
        }
        Long userId = user.getId();
        // 2.判断当前登录用户是否已经点赞
        String key = "blog:liked:" + blog.getId();
        Boolean ismember = stringRedisTemplate.opsForSet().ismember(key, userId.toString());
        blog.setIsLike(BooleanUtil,isTrue(ismember));
    }

点赞排行榜

我们分析一下需求,要求返回最早点的前5名,而set集合里面的排序是无序的,无法满足。list集合满足先进先出,那只能显示最后五个点赞的用户同时链表不满足唯一性,也无法快速查询用户id  。最后sortedset是根据score值,这个score值可以自己定义,将score值定义为时间戳,越小的越在前,满足要求

所以对点赞功能做一些修改

1.set数据结构改为sortedset数据结构

2.将ismember改为判断分数大小,可以显示最早点赞的前5名

@Override
    public Result likeBlog(Long id) {
        // 1.获取登录用户
        Long userId = UserHolder.getUser().getId();
        // 2.判断当前登录用户是否已经点赞
        String key = BLOG_LIKED_KEY + id;
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
        if (score == null) {
            // 3.如果未点赞,可以点赞
            // 3.1.数据库点赞数 + 1
            boolean isSuccess = update().setSql("liked = liked + 1").eq("id", id).update();
            // 3.2.保存用户到Redis的set集合  zadd key value score
            if (isSuccess) {
                stringRedisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis());
            }
        } else {
            // 4.如果已点赞,取消点赞
            // 4.1.数据库点赞数 -1
            boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();
            // 4.2.把用户从Redis的set集合移除
            if (isSuccess) {
                stringRedisTemplate.opsForZSet().remove(key, userId.toString());
            }
        }
        return Result.ok();

同样,判断是否点赞成功 也修改为sortedset数据结构和分数设置

private void isBlogLiked(Blog blog) {
        // 1.获取登录用户
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            // 用户未登录,无需查询是否点赞
            return;
        }
        Long userId = user.getId();
        // 2.判断当前登录用户是否已经点赞
        String key = "blog:liked:" + blog.getId();
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
        blog.setIsLike(score != null);
    }

实现点赞排行榜

    @Override
    public Result queryBlogLikes(Long id) {
        String key = BLOG_LIKED_KEY + id;
        // 1.查询top5的点赞用户 zrange key 0 4
        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(Long::valueOf).collect(Collectors.toList());
        String idStr = StrUtil.join(",", ids);
        // 3.根据用户id查询用户 WHERE id IN ( 5 , 1 ) ORDER BY FIELD(id, 5, 1)
        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);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值