点赞
编写返回点赞key的工具
某个实体的赞,需要传入实体的类型,实体id
public class RedisKeyUtill {
private static final String SPILT=":";
private static final String PREFIX_ENTITY_LIKE="like:entity";
// 某个实体的赞
// like:entity:entityType:entityId -> set(userId)
public static String getEntityLikeKey(int entityType,int entityId)
{
return PREFIX_ENTITY_LIKE+SPILT+entityType+SPILT+entityId;
}
}
编写Service实现点赞业务
- 集合的元素是不重复的,所有可以根据userId找到对应的唯一用户,根据用户的数量可以得出点赞的数量
- 集合的key是每一个实体对应的唯一key 比如传入帖子id,这个帖子就生成了一个唯一key
- 判断用户有没有点过赞 看集合里有没有对应的userId 如果已经点赞就移除该用户,取消赞
@Service
public class LikeService {
@Autowired
RedisTemplate redisTemplate;
//点赞业务
public void Like(int userId,int entityType,int entityId)
{
//获取key 例如获取指定id帖子的key
String entityLikeKey= RedisKeyUtill.getEntityLikeKey(entityType,entityId);
//判断该用户是否已经点过赞
if(redisTemplate.opsForSet().isMember(entityLikeKey,userId))
{
redisTemplate.opsForSet().remove(entityLikeKey,userId);
}else {
redisTemplate.opsForSet().add(entityLikeKey,userId);
}
}
// 查询某实体点赞的数量
public long findEntityLikeCount(int entityType, int entityId) {
//获取key 例如获取指定id帖子的key
String entityLikeKey= RedisKeyUtill.getEntityLikeKey(entityType,entityId);
return redisTemplate.opsForSet().size(entityLikeKey);
}
// 查询某人对某实体的点赞状态
public int findEntityLikeStatus(int userId, int entityType, int entityId) {
//获取key 例如获取指定id帖子的key
String entityLikeKey= RedisKeyUtill.getEntityLikeKey(entityType,entityId);
return redisTemplate.opsForSet().isMember(entityLikeKey,userId)?1:0;
}
}
编写Controller
@Controller
public class LikeController {
@Autowired
private LikeService likeService;
@Autowired
private HostHolder hostHolder;
//点赞是异步请求,需要返回JSON字符串
@RequestMapping(path = "/like", method = RequestMethod.POST)
@ResponseBody
public String like(int entityType, int entityId) {
User user = hostHolder.getUser();
//点赞
likeService.Like(user.getId(),entityType,entityId);
// 数量
long likeCount=likeService.findEntityLikeCount(entityType,entityId);
// 状态
int likeStatus = likeService.findEntityLikeStatus(user.getId(), entityType, entityId);
// 返回的结果
Map<String, Object> map = new HashMap<>();
map.put("likeCount", likeCount);
map.put("likeStatus", likeStatus);
return CommunityUtil.getJSONString(0, null, map);
}
}
修改页面
处理异步请求 把超链接当做按钮来用 编写js 拼接变量
this 知道哪一个赞 处理三个地方的赞
新建js文件
<a href="javascript:;" th:onclick="|like(this,1,${post.id});|" class="text-primary">
<b th:text="${likeStatus==1?'已赞':'赞'}">赞</b> <i th:text="${likeCount}">11</i>
</a>
function like(btn,entityType,entityId) {
$.post(
CONTEXT_PATH+"/like",
{"entityType":entityType,"entityId":entityId},
function (data) {
data=$.parseJSON(data);
if(data.code==0)
{
$(btn).children("i").text(data.likeCount);
$(btn).children("b").text(data.likeStatus==1?'已赞':"赞");
}else
{
alert(data.msg);
}
}
)
}
2、修改主页帖子点赞的数量
@RequestMapping(value = "/index",method = RequestMethod.GET)
public String getIndexPage(Model model, Page page)
{
//不需要向model中添加page对象 因为方法调用前,SpringMvc会自动实例化Model和Page,并将Page注入Model
// 所以,在Thymeleaf中可以直接访问Page对象中的数据
//获取总行数
page.setRows(discussPostService.countDiscussPosts(0));
page.setPath("/index");
//获取帖子数据
List<DiscussPost> list = discussPostService.findDiscussPosts(0, page.getOffset(),page.getLimit());
//创建新集合
List<Map<String,Object>> discussPosts=new ArrayList<>();
//遍历list
if(list!=null)
{
for(DiscussPost post:list)
{
Map<String,Object> map=new HashMap<>();
map.put("post",post);
User user = userService.queryUserById(post.getUserId());
map.put("user",user);
//查询帖子点赞的数量
long entityLikeCount = likeService.findEntityLikeCount(post.getType(), post.getId());
map.put("likeCount",entityLikeCount);
discussPosts.add(map);
}
}
model.addAttribute("discussPosts",discussPosts);
return "/index";
}
<li class="d-inline ml-2" >赞 <span th:text="${map.likeCount}">11</span></li>
3、修改每个帖子详情,每个评论,每个回复点赞的数量和状态
//点赞数量
long entityLikeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, id);
model.addAttribute("likeCount",entityLikeCount);
//点赞状态
int likeStatus=hostHolder.getUser()==null?0:
likeService.findEntityLikeStatus(hostHolder.getUser().getId(),ENTITY_TYPE_POST,id);
model.addAttribute("likeStatus",likeStatus);
我收到的赞
重构点赞功能
以用户id为key来存放到Redis中,重构点赞功能,点赞的时候传入被赞人的用户id,如果是点赞就使该key的count加一,如果是取消赞就使被点赞人的key的值减
使用Redis事务
获取被赞人的id 不使用通过实体获取userid的方法,需要访问数据库 与redis的高性能相反
传入参数被赞人id 把查询放在事务之外
// 点赞
public void like(int userId, int entityType, int entityId, int entityUserId) {
redisTemplate.execute(new SessionCallback() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
String userLikeKey = RedisKeyUtil.getUserLikeKey(entityUserId);
//判断用户是否已经点赞
boolean isMember = operations.opsForSet().isMember(entityLikeKey, userId);
operations.multi();
if (isMember) {
//如果已经点赞 移除赞
//被点赞的用户的count减一
operations.opsForSet().remove(entityLikeKey, userId);
operations.opsForValue().decrement(userLikeKey);
} else {
//没有点赞
//被点赞的用户的count加一
operations.opsForSet().add(entityLikeKey, userId);
operations.opsForValue().increment(userLikeKey);
}
return operations.exec();
}
});
}
// 查询某个用户获得的赞
public int findUserLikeCount(int userId) {
String userLikeKey = RedisKeyUtil.getUserLikeKey(userId);
Integer count = (Integer) redisTemplate.opsForValue().get(userLikeKey);
return count == null ? 0 : count.intValue();
}
个人主页
// 个人主页
@RequestMapping(path = "/profile/{userId}", method = RequestMethod.GET)
public String getProfilePage(@PathVariable("userId") int userId, Model model) {
User user = userService.queryUserById(userId);
if (user == null) {
throw new RuntimeException("该用户不存在!");
}
// 用户
model.addAttribute("user", user);
// 点赞数量
int likeCount = likeService.findUserLikeCount(userId);
model.addAttribute("likeCount", likeCount);
return "/site/profile";
}