86:第七章:开发前台首页、作家个人展示页、粉丝等功能:7:【查看是否已关注某用户,接口】、【关注,接口】、【取关,接口】;(核心:对于一些热点的、需要频繁+-的数据,也可以存在Redis中;)

该博客介绍了如何使用Redis的累加和累减功能来优化粉丝功能,避免频繁使用数据库聚合函数导致的压力。详细阐述了关注和取关接口的开发过程,包括在用户服务中的实现,以及如何通过Redis来同步更新用户的关注数和粉丝数,以提高系统性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明:

(1)本篇博客开发的内容:【查看是否已关注某用户,接口】、【关注,接口】、【取关,接口】;

(2)本篇博客就一个点:对于那些需要频繁写的小数据,也可以存到Redis中,直接在Redis中增改;

目录

一:粉丝功能,技术选择:利用Redis的"累加"、"累减"来统计用户的关注数和粉丝数;(从而消除使用聚合函数操作数据,给数据库带来的压力)

二:开发【假如当前登录用户是A,当A查看B的主页时,查询A是否已经关注B,接口】;

1.该部分,内容说明;

2.开发【查询当前登录用户,是否已经关注当前查看页面的作家,接口】;

(1)在【api】接口工程中,创建MyFansControllerApi接口,并定义【查询当前登录用户,是否已经关注当前查看页面的作家,接口】;

(2)在【user】用户服务中,创建MyFansController类,去实现【查询当前登录用户,是否已经关注当前查看页面的作家,接口】;

(3)在【user】用户服务中,创建MyFansService接口,定义一个查询当前登录用户是否关注的方法;然后,创建MyFansServiceImpl实现类,去实现这个方法;

3.效果;

三:开发【A用户关注B用户,A的关注数+1,B的粉丝数+1,接口】;

1.在【api】接口工程的MyFansControllerApi接口,定义【A用户关注B用户,A的关注数+1,B的粉丝数+1,接口】; 

2.在【user】用户服务的MyFansController类中,去实现【A用户关注B用户,A的关注数数+1,B的粉丝数+1,接口】;

3.在【user】用户服务的MyFansService接口,定义一个方法;然后,在MyFansServiceImpl实现类,去实现这个方法;

4.效果;

四:开发【A用户取关B用户,A的关注数-1,B的粉丝数-1,接口】; 

 1.在【api】接口工程的MyFansControllerApi接口,定义【A用户取关B用户,A的关注数-1,B的粉丝数-1,接口】; 

2.在【user】用户服务的MyFansController类中,去实现【A用户取关B用户,A的关注数-1,B的粉丝数-1,接口】;

3.在【user】用户服务的MyFansService接口,定义一个方法;然后,在MyFansServiceImpl实现类,去实现这个方法;

4.效果;

附加:【关注,接口】和【取关,接口】都需要,“用户登录、并且用户是激活状态”才能操作;所以,在【api】接口工程的InterceptorConfig类中,对其进行配置;


一:粉丝功能,技术选择:利用Redis的"累加"、"累减"来统计用户的关注数和粉丝数;(从而消除使用聚合函数操作数据,给数据库带来的压力)

已知,在MariaDB中有一个fans表;

(1)统计某个用户的关注数和粉丝数,直接的想法是count()的方式去查询fans表;

(2)但是,由于前台门户端的并发量将会很高;也将会有很多人查看别人的个人展示页;那么,就会频繁的count()查询fans表;

(3)而这是不好的(尤其是数据量很大的时候),数据库的压力会很大;(在【附加:数据的聚合函数,会给数据库造成很大压力;】中,对此进行了介绍)

(4)所以,针对这个具体的业务而言,我们会利用Redis来优化,减轻数据库压力;

(1)对于Redis来说,前面我们使用Redis存放过热点数据;即,都是redis这款nosql数据库,作为缓存来使用;

(2)但是,Redis本身就是一款nosql;我们,自然可以把其当成数据库来使用;

(3)某个用户的【关注数】、【粉丝数】的累加和类减,可以通过Redis来实现;(Redis具体处理任务的时候,是单线程的,所以其实安全的)

(4)Redis中,底层有INCR(对某个值加1)和DECR(对某个值减1)两个命令;

          ● 比如用户1001,可以在Redis中创建一个【1001:fans,fansNum】数据,记录用户的粉丝数;

          ● 如果有人关注了1001,那么这个值就加1;

          ● 如果有人取关了1001,那么这个值就减1;

          ● 用户的关注数,同理;


二:开发【假如当前登录用户是A,当A查看B的主页时,查询A是否已经关注B,接口】;

1.该部分,内容说明;

而【我是慕课网】是否关注【慕小健】,是需要去数据库表中查询的;

2.开发【查询当前登录用户,是否已经关注当前查看页面的作家,接口】;

(1)在【api】接口工程中,创建MyFansControllerApi接口,并定义【查询当前登录用户,是否已经关注当前查看页面的作家,接口】;

package com.imooc.api.controller.user;


import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;


@Api(value = "粉丝管理",tags = {"粉丝管理功能的controller"})
@RequestMapping("fans")  //设置路由,这个是需要前后端约定好的;
public interface MyFansControllerApi {

    /**
     * 假如当前登录用户是A,当A查看B的主页时,查询A是否已经关注B;
     * @param writerId
     * @param fanId
     * @return
     */
    @ApiOperation(value = "查询当前登录用户,是否已经关注当前查看页面的作家", notes = "查询当前登录用户,是否已经关注当前查看页面的作家", httpMethod = "POST")
    @PostMapping("/isMeFollowThisWriter")
    public GraceJSONResult hello(@RequestParam String writerId,
                        @RequestParam String fanId);
}

说明:

(1)这个接口的url、请求方式、参数需要前后端保持一致;

(2)在【user】用户服务中,创建MyFansController类,去实现【查询当前登录用户,是否已经关注当前查看页面的作家,接口】;

package com.imooc.user.controller;

import com.imooc.api.BaseController;
import com.imooc.api.controller.user.MyFansControllerApi;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.user.service.MyFansService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyFansController extends BaseController implements MyFansControllerApi {

    final static Logger logger = LoggerFactory.getLogger(MyFansController.class);

    @Autowired
    private MyFansService myFansService;


    /**
     * 假如当前登录用户是A,当A查看B的主页时,查询A是否已经关注B;
     * @param writerId
     * @param fanId
     * @return
     */
    @Override
    public GraceJSONResult isMeFollowThisWriter(String writerId, String fanId) {
//这儿需要加一个writerId和fanId判空的处理
        boolean isFollow = myFansService.isMeFollowThisWriter(writerId, fanId);
        return GraceJSONResult.ok(isFollow);
    }
}

(3)在【user】用户服务中,创建MyFansService接口,定义一个查询当前登录用户是否关注的方法;然后,创建MyFansServiceImpl实现类,去实现这个方法;

package com.imooc.user.service;

public interface MyFansService {

    /**
     * 假如当前登录用户是A,当A查看B的主页时,查询A是否已经关注B;
     */
    public boolean isMeFollowThisWriter(String writerId, String fanId);
}
package com.imooc.user.service.impl;

import com.imooc.api.service.BaseService;
import com.imooc.bo.UpdateUserInfoBO;
import com.imooc.enums.Sex;
import com.imooc.enums.UserStatus;
import com.imooc.exception.GraceException;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.pojo.AppUser;
import com.imooc.pojo.Fans;
import com.imooc.user.mapper.AppUserMapper;
import com.imooc.user.mapper.FansMapper;
import com.imooc.user.service.MyFansService;
import com.imooc.user.service.UserService;
import com.imooc.utils.DateUtil;
import com.imooc.utils.DesensitizationUtil;
import com.imooc.utils.JsonUtils;
import com.imooc.utils.RedisOperator;
import org.n3r.idworker.Sid;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;

@Service
public class MyFansServiceImpl extends BaseService implements MyFansService {

    @Autowired
    FansMapper fansMapper;
    /**
     * 假如当前登录用户是A,当A查看B的主页时,查询A是否已经关注B;
     */
    @Override
    public boolean isMeFollowThisWriter(String writerId, String fanId) {

        //根据传过来的参数,构建一个Fans对象;
        Fans fans = new Fans();
        fans.setFanId(fanId);
        fans.setWriterId(writerId);

        //然后,去数据库的fans表中,查查看是否有满足这种条件的记录;
        int count = fansMapper.selectCount(fans);

        return count > 0;
    }
}

(1)记得使用【15:第二章:架构后端项目:11:使用【mybatis-generator-core】依赖生成实体类、mapper接口、mapper.xml等逆向文件;(我们使用tkmybatis来帮助提升开发效率)】这个工程,针对fans表生成对应的mapper接口、xml、实体类;

(2)这儿我们查询的时候,使用了selectCount()方法,即这儿底层其实也是使用了SQL的count函数;即,这儿是不好的;;;;后面,我们使用elasticsearch的时候,我们会把粉丝的数据保存到elasticsearch中,所以后面这儿我们会优化;

(3)fans表的结构;这个表其实是有点冗余的,但是这个冗余是为了后面方便的,所以这个冗余是有价值的;

3.效果;

(1)先install一下整个项目;(2)记得使用SwitchHost开启虚拟域名映射;(3)使用Tomcat启动前端项目;(4)然后,启动后端项目; 



三:开发【A用户关注B用户,A的关注数+1,B的粉丝数+1,接口】;

PS:按理说A用户是不能关注自己的;;;但是,这儿我们因为懒,就没有对这一点做控制;;;

1.在【api】接口工程的MyFansControllerApi接口,定义【A用户关注B用户,A的关注数+1,B的粉丝数+1,接口】; 

    /**
     * A用户关注B用户,A的粉丝数+1;
     * @param writerId
     * @param fanId
     * @return
     */
    @ApiOperation(value = "A用户关注B用户,A的粉丝数+1", notes = "A用户关注B用户,A的粉丝数+1", httpMethod = "POST")
    @PostMapping("/follow")
    public GraceJSONResult follow(@RequestParam String writerId,
                                                @RequestParam String fanId);

 说明:

(1)

2.在【user】用户服务的MyFansController类中,去实现【A用户关注B用户,A的关注数数+1,B的粉丝数+1,接口】;

    /**
     * A用户关注B用户,A的关注数数+1,B的粉丝数+1;
     * @param writerId
     * @param fanId
     * @return
     */
    @Override
    public GraceJSONResult follow(String writerId, String fanId) {
        //这儿需要加一个writerId和fanId判空的处理

        myFansService.follow(writerId, fanId);
        return GraceJSONResult.ok();
    }

3.在【user】用户服务的MyFansService接口,定义一个方法;然后,在MyFansServiceImpl实现类,去实现这个方法;

    /**
     * A用户关注B用户,A的关注数数+1,B的粉丝数+1;
     * @param writerId
     * @param fanId
     * @return
     */
    public void follow(String writerId, String fanId);

……………………………………………………

    /**
     * A用户关注B用户,A的关注数数+1,B的粉丝数+1;
     *
     * @param writerId
     * @param fanId
     * @return
     */
    @Transactional
    @Override
    public void follow(String writerId, String fanId) {

        Fans fans = new Fans();

        AppUser appUser = userService.getUser(fanId);//根据粉丝id,去查询该粉丝的详细信息
        String fanPkId = sid.nextShort();//通过雪花算法,得到一个fans表记录的id

        //然后,根据fans表的要求,去设置信息
        fans.setId(fanPkId);
        fans.setFanId(fanId);
        fans.setWriterId(writerId);
        fans.setFace(appUser.getFace());
        fans.setFanNickname(appUser.getNickname());
        fans.setProvince(appUser.getProvince());
        fans.setSex(appUser.getSex());
        fansMapper.insert(fans);//插入数据库


        //然后,A的关注数需要+1,B的粉丝数要+1;
        //B的粉丝数+1;(如果这个key不存在,就去创建)
        redisOperator.increment(REDIS_WRITER_FANS_COUNT + ":" + writerId, 1);
        //A的关注数+1;
        redisOperator.increment(REDIS_MY_FOLLOW_COUNT + ":" + fanId, 1);

    }

说明:

(0)关注数和粉丝数,这种既需要频繁查询,又需要频繁增改的小数据;我们也使用了Redis;

(1)我们在【api】接口工程的BaseService类中,定义了两个常量,让其作为向Redis中存放数据时,key的前半部分;

4.效果;

(1)先install一下整个项目;(2)记得使用SwitchHost开启虚拟域名映射;(3)使用Tomcat启动前端项目;(4)然后,启动后端项目; 


四:开发【A用户取关B用户,A的关注数-1,B的粉丝数-1,接口】; 

 1.在【api】接口工程的MyFansControllerApi接口,定义【A用户取关B用户,A的关注数-1,B的粉丝数-1,接口】; 

    /**
     * A用户取关B用户,A的关注数数-1,B的粉丝数-1;
     * @param writerId:当前被查看主页的用户;(换句话说,将要被取关的用户)
     * @param fanId:当前登录的用户;(换句话说,将要取关别人的,用户)
     * @return
     */
    @ApiOperation(value = "A用户取关B用户,A的关注数数-1,B的粉丝数-1", notes = "A用户取关B用户,A的关注数数-1,B的粉丝数-1", httpMethod = "POST")
    @PostMapping("/follow")
    public GraceJSONResult unFollow(@RequestParam String writerId,
                                  @RequestParam String fanId);

 说明:

(1)

 

2.在【user】用户服务的MyFansController类中,去实现【A用户取关B用户,A的关注数-1,B的粉丝数-1,接口】;

    /**
     * A用户取关B用户,A的关注数数-1,B的粉丝数-1;
     * @param writerId:当前被查看主页的用户;(换句话说,将要被取关的用户)
     * @param fanId:当前登录的用户;(换句话说,将要取关别人的,用户)
     * @return
     */
    @Override
    public GraceJSONResult unFollow(String writerId, String fanId) {

        //这儿需要加一个writerId和fanId判空的处理
        myFansService.unFollow(writerId, fanId);
        return GraceJSONResult.ok();
    }

3.在【user】用户服务的MyFansService接口,定义一个方法;然后,在MyFansServiceImpl实现类,去实现这个方法;

    /**
     * A用户取关B用户,A的关注数数-1,B的粉丝数-1;
     * @param writerId
     * @param fanId
     * @return
     */
    public void unFollow(String writerId, String fanId);

……………………………………………………

    /**
     * A用户取关B用户,A的关注数数-1,B的粉丝数-1;
     *
     * @param writerId
     * @param fanId
     * @return
     */
    @Transactional
    @Override
    public void unFollow(String writerId, String fanId) {
        Fans fans = new Fans();
        fans.setWriterId(writerId);
        fans.setFanId(fanId);

        fansMapper.delete(fans);//删除fans表中的记录

        //然后,A的关注数需要-1,B的粉丝数要-1;
        //B的粉丝数-1;(如果这个key不存在,就去创建)
        redisOperator.decrement(REDIS_WRITER_FANS_COUNT + ":" + writerId, 1);
        //A的关注数-1;
        redisOperator.decrement(REDIS_MY_FOLLOW_COUNT + ":" + fanId, 1);

    }

4.效果;

(1)先install一下整个项目;(2)记得使用SwitchHost开启虚拟域名映射;(3)使用Tomcat启动前端项目;(4)然后,启动后端项目; 

 

同时,在Redis中的数据,也是OK的;


附加:【关注,接口】和【取关,接口】都需要,“用户登录、并且用户是激活状态”才能操作;所以,在【api】接口工程的InterceptorConfig类中,对其进行配置;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值