Redis的应用实例:关注和粉丝的 实现
前言:
我们知道,关注和粉丝已经成为很多信息流平台必备的功能,比如我们的csdn就有这一功能,但是随着关注人的增加,我们如果采用普通数据库的存储可能会满足不了用户的速度上的体验,如:MySQL数据存储是存储在表中,查找数据时要先对表进行全局扫描或者根据索引查找,这涉及到磁盘的查找,磁盘查找如果是按条点查找可能会快点,但是顺序查找就比较慢;而Redis不用这么麻烦,本身就是存储在内存中,会根据数据在内存的位置直接取出。
那么Redis它有什么优势呢?
1:读写性能极高 , redis读对的速度是11万次/s , 写的速度是8.1万次/s.
2:redis 支持多种数据类型,redis存储的是 key–value格式的数据,其中key是字符串,但是value就有多种数据类型了:String , list ,map , set ,有序集合(sorted set)
3:非关系性数据库
4:持久化:redis的持久化方式有rdb和 aof 两种,rdb 是将内存中的数据压缩后写入到硬盘上,aof是将日志整理写到硬盘中,而且通过设置可以设置不同的持久化方式,有效的减轻了服务器的压力,同时在很大程度上防止了数据的丢失。
所以我们在涉及到互粉、点赞等数据读写和存储性能要求比高的功能,我们尽量用Redis去解决这些问题!
Redis存放数据的方法:key-value对的形式
这里我们就依据互粉功能来看一下怎么实现Redis的数据存储的吧!
实现功能:
关注列表 粉丝列表 关注数 粉丝数 关注 取消关注
1.在biuld.gradle引包
implementation('org.springframework.boot:spring-boot-starter-data-redis')
2.写一个方法类:
RedisHelper 主要用来存放Redis的一些基本方法
public Map<Object, Object> getHash(String key){
return mRedisTemplate.opsForHash().entries(key);
}
public void hset(String key, String hashKey, Object value){
mRedisTemplate.opsForHash().put(key, hashKey, value);
}
关于Resdis的类型用法详戳:Redis的五种数据类型及方法
public void hdel(String key, String...hashKeys) { //...代表可以有一个参数,也可以有多个参数!
mRedisTemplate.opsForHash().delete(key, hashKeys);
}
public Long hLen(String key) {
return mRedisTemplate.opsForHash().size(key);
}
3.然后我们建立一个 RedisFollowHelper 主要用来存放关注与取消关注的方法实现!
import com.nschool.api.model.User;
import com.nschool.api.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class RedisFollowHelper {
//爱豆(FOLLOW_USERS) 的粉丝表
private static final String FOLLOW_USERS = "USER_%s:myFans";
//脑残粉(FANS_USERS) 的关注表
private static final String FANS_USERS = "USER_%s:myFollows";
@Autowired
RedisHelper redisHelper;
@Autowired
UserService mUserService;
//userId去关注别人,判断是否已关注
public boolean isFollowed(Long followId, User user) {
String fanUsersKey = String.format(FANS_USERS, user.getId());
Object value = redisHelper.hget(fanUsersKey, String.valueOf(followId));
return value != null ;
}
//followId去关注别人,判断是否已关注
public boolean isFollowedByFollowId(Long followId, User user) {
String fanUsersKey = String.format(FANS_USERS, followId);
Object value = redisHelper.hget(fanUsersKey, String.valueOf(user.getId()));
return value != null ;
}
public void follow(Long followId, User user) {
User followUser = mUserService.getUserById(followId);
//粉丝的爱豆们
String followUsersKey = String.format(FOLLOW_USERS, followId);
redisHelper.hset(followUsersKey, String.valueOf(user.getId()), user.getUsername());
//爱豆的粉丝们
String fanUsersKey = String.format(FANS_USERS, user.getId());
redisHelper.hset(fanUsersKey, String.valueOf(followId), followUser.getUsername());
}
public void unFollow(Long followId, User user) {
User followUser = mUserService.getUserById(followId);
//粉丝的爱豆们
String followUsersKey = String.format(FOLLOW_USERS, followId);
redisHelper.hdel(followUsersKey, String.valueOf(user.getId()), user.getUsername());
//爱豆的粉丝们
String fanUsersKey = String.format(FANS_USERS, user.getId());
redisHelper.hdel(fanUsersKey, String.valueOf(followId), followUser.getUsername());
}
public Map<Object,Object> myFollows(Long userId){
String fansUsersKey = String.format(FANS_USERS,userId);
Map<Object,Object> objectMap = redisHelper.getHash(fansUsersKey);
return objectMap;
}
public Map<Object,Object> myFans(Long followId){
String followUsersKey = String.format(FOLLOW_USERS, followId);
Map<Object,Object> objectMap = redisHelper.getHash(followUsersKey);
return objectMap;
}
public Long myFollowCount(Long userId){
String fansCountKey = String.format(FANS_USERS, userId);
Long fansCount= redisHelper.hLen(fansCountKey);
return fansCount;
}
public Long myFansCount(Long followId){
String followCountKey = String.format(FOLLOW_USERS, followId);
Long followCount= redisHelper.hLen(followCountKey);
return followCount;
}
}
4.创建userService类 对关注接口的业务逻辑进行进一步的设计
@Service
public class UserService extends BaseService {
/**
*
* @param followId 关注人的ID
* @param user 去关注人的ID
*/
@Transactional
public boolean isFollowed(Long followId, User user) {
return redisFollowHelper.isFollowed(followId, user);
}
@Transactional
public void follow(Long followId, User user) {
redisFollowHelper.follow(followId, user);
}
@Transactional
public void unFollow(Long followId, User user) {
redisFollowHelper.unFollow(followId, user);
}
@Transactional
public List<FollowUserResp> myFollows(){
Long userId=getCurrentUserId();
return getFriendList(userId,redisFollowHelper.myFollows(userId));
}
@Transactional
public List<FollowUserResp> myFans(){
Long followId=getCurrentUserId();
return getFriendList(followId,redisFollowHelper.myFans(followId));
}
private boolean isFollowedByFollowId(Long followId, User user) {
return redisFollowHelper.isFollowedByFollowId(followId, user);
}
@Transactional
public Long myFollowCount(Long targetUserId){
targetUserId=getTargetCount(targetUserId);
Long count = redisFollowHelper.myFollowCount(targetUserId);
return count;
}
@Transactional
public Long myFansCount(Long targetUserId){
targetUserId=getTargetCount(targetUserId);
Long count = redisFollowHelper.myFansCount(targetUserId);
return count;
}
/**
* 获得用户关注或者粉丝列表
* @param currUserId 当前用户
* @param objectMap 调用方法
* @return
*/
private List<FollowUserResp> getFriendList(Long currUserId, Map<Object,Object> objectMap){
List<FollowUserResp> followUserRespList = new ArrayList<>();
for (Map.Entry<Object, Object> entity :
objectMap.entrySet()) {
Object key = entity.getKey();
Long id = Long.valueOf(String.valueOf(key));
User user = getUserById(id);
FollowUserResp followUserResp = new FollowUserResp();
followUserResp.setId(user.getId());
followUserResp.setUsername(user.getUsername());
followUserResp.setAvatar(user.getAvatar());
followUserResp.setGender(user.getGender());
if (isFollowedByFollowId(currUserId, user)) {
followUserResp.setFollowed(true);
} else{
followUserResp.setFollowed(false);}
followUserRespList.add(followUserResp);
}
return followUserRespList;
}
}
5.创建userController类,作为接口调用类
@RestController
@RequestMapping("user")
@Api(value = "用户接口", tags = {"用户接口"})
public class UserController extends BaseController {
@Autowired
UserService mUserService;
@ApiOperation(value = "关注", notes = "关注")
@PostMapping("follow")
public Result follow(
@RequestParam Long followId
){
User user = getCurrentUser();
if (mUserService.isFollowed(followId, user)) {
return Result.success( "您已经关注!");
}
mUserService.follow(followId, user);
return Result.success( "感谢亲的关注!");
}
@ApiOperation(value = "取消关注", notes = "取消关注")
@PostMapping("unFollow")
public Result unFollow(
@RequestParam Long followId
){
User user = getCurrentUser();
if (!mUserService.isFollowed(followId, user)) {
return Result.success( "您已经取消关注!");
}
mUserService.unFollow(followId, user);
return Result.success("取消关注") ;
}
@ApiOperation(value = "加载关注列表",notes = "加载关注列表")
@GetMapping("myFollow")
public Result<List<FollowUserResp>> myFollows(){
List<FollowUserResp> followUserResp = mUserService.myFollows();
return Result.success(followUserResp);
}
@ApiOperation(value = "加载粉丝列表",notes = "加载粉丝列表")
@GetMapping("myFans")
public Result<List<FollowUserResp>> myFans(){
List<FollowUserResp> followUserResp = mUserService.myFans();
return Result.success(followUserResp);
}
@ApiOperation(value = "获取关注数",notes = "获取关注数")
@GetMapping("myFollowCount")
public Result<Long> myFollowCount(
@RequestParam (value = "targetUserId",required = false)Long targetUserId
){
Long count = mUserService.myFollowCount(targetUserId);
return Result.success(count);
}
@ApiOperation(value = "获取粉丝数",notes = "获取粉丝数")
@GetMapping("myFansCount")
public Result<Long> myFansCount(
@RequestParam (value = "targetUserId",required = false)Long targetUserId
){
Long count = mUserService.myFansCount(targetUserId);
return Result.success(count);
}
}