课程说明
- 抽取common工程
- 圈子功能说明
- 圈子技术实现
- 圈子技术方案
- 圈子实现发布动态
- 圈子实现好友动态
- 圈子实现推荐动态
1、抽取common工程
在项目中一般需要将公用的对象进行抽取放到common工程中,其他的工程依赖此工程即可。下面我们将sso以及server工程中的公用的对象进行抽取。
1.1、创建my-tanhua-common工程
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>my-tanhua</artifactId>
<groupId>cn.itcast.tanhua</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-tanhua-common</artifactId>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
</project>
1.2、通用枚举
将SexEnum枚举移动至common工程,并且后续创建的枚举也要放到次工程中,以达到公用的目的。
package com.tanhua.common.enums;
import com.baomidou.mybatisplus.core.enums.IEnum;
public enum SexEnum implements IEnum<Integer> {
MAN(1,"男"),
WOMAN(2,"女"),
UNKNOWN(3,"未知");
private int value;
private String desc;
SexEnum(int value, String desc) {
this.value = value;
this.desc = desc;
}
@Override
public Integer getValue() {
return this.value;
}
@Override
public String toString() {
return this.desc;
}
}
需要修改server与sso工程中的application.properties配置:
# 枚举包扫描
mybatis-plus.type-enums-package=com.tanhua.common.enums
将server与sso工程中的SexEnum对象删除以及将相关的类引用进行修改。
1.3、抽取mapper
需要将UserInfoMapper以及UserMapper放置到common工程的com.tanhua.common.mapper包下。
package com.tanhua.common.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tanhua.common.pojo.User;
public interface UserMapper extends BaseMapper<User> {
}
package com.tanhua.common.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tanhua.common.pojo.UserInfo;
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
说明:抽取完成后,需要将原工程的代码删除以及修改其他代码中引入的依赖。
1.4、抽取pojo
将BasePojo、User、UserInfo移动至common工程:
1.5、抽取utils
将server工程的utils进行抽取公用,后续的工具类也放置到common工程中。
抽取完成后进行测试,确保可以正常启动以及功能都正常。
2、圈子功能
2.1、功能说明
探花交友项目中的圈子功能,类似微信的朋友圈,基本的功能为:发布动态、浏览好友动态、浏览推荐动态、点赞、评论、喜欢等功能。
发布:
2.2、实现方案分析
对于圈子功能的实现,我们需要对它的功能特点做分析:
- 数据量会随着用户数增大而增大
- 读多写少,一般而言,浏览朋友圈动态会多一些,发动态相对就会少一些
- 非好友看不到其动态内容
- ……
针对以上特点,我们来分析一下:
- 对于数据量大而言,显然不能够使用关系型数据库进行存储,我们需要通过MongoDB进行存储
- 对于读多写少的应用,尽可能的减少读取数据的成本
- 比如说,一条SQL语句,单张表查询一定比多张表查询要快
- 条件越多的查询速度将越慢,尽可能的减少条件以提升查询速度
所以对于存储而言,主要是核心的4张表:
- 发布表:记录了所有用户的发布的东西信息,如图片、视频等。
- 相册:相册是每个用户独立的,记录了该用户所发布的所有内容。
- 评论:针对某个具体发布的朋友评论和点赞操作。
- 时间线:所谓“刷朋友圈”,就是刷时间线,就是一个用户所有的朋友的发布内容。
流程:
流程说明:
- 用户发布动态,动态中一般包含了图片和文字,图片上传到阿里云,上传成功后拿到图片地址,将文字和图片地址进行持久化存储
- 首先,需要将动态数据写入到发布表中,其次,再写入到自己的相册表中,需要注意的是,相册表中只包含了发布id,不会冗余存储发布数据
- 最后,需要将发布数据异步的写入到好友的时间线表中,之所以考虑异步操作,是因为希望发布能够尽快给用户反馈,发布成功
- 好友刷朋友圈时,实际上只需要查询自己的时间线表即可,这样最大限度的提升了查询速度,再配合redis的缓存,那速度将是飞快的
- 用户在对动态内容进行点赞、喜欢、评论操作时,只需要写入到评论表即可,该表中也是只会记录发布id,并不会冗余存储发布数据
2.3、表结构设计
发布表:
#表名:quanzi_publish
{
"_id":"5fae53d17e52992e78a3db61",#主键id
"pid":1001, #发布id(Long类型)
"userId":1, #用户id
"text":"今天心情很好", #文本内容
"medias":"http://xxxx/x/y/z.jpg", #媒体数据,图片或小视频 url
"seeType":1, #谁可以看,1-公开,2-私密,3-部分可见,4-不给谁看
"seeList":[1,2,3], #部分可见的列表
"notSeeList":[4,5,6],#不给谁看的列表
"longitude":108.840974298098,#经度
"latitude":34.2789316522934,#纬度
"locationName":"上海市浦东区", #位置名称
"created",1568012791171 #发布时间
}
相册表:
#表名:quanzi_album_{
userId}
{
"_id":"5fae539d7e52992e78a3b684",#主键id
"publishId":"5fae53d17e52992e78a3db61", #发布id
"created":1568012791171 #发布时间
}
时间线表:
#表名:quanzi_time_line_{
userId}
{
"_id":"5fae539b7e52992e78a3b4ae",#主键id,
"userId":2, #好友id
"publishId":"5fae53d17e52992e78a3db61", #发布id
"date":1568012791171 #发布时间
}
评论表:
#表名:quanzi_comment
{
"_id":"5fae539d7e52992e78a3b648", #主键id
"publishId":"5fae53d17e52992e78a3db61", #发布id
"commentType":1, #评论类型,1-点赞,2-评论,3-喜欢
"content":"给力!", #评论内容
"userId":2, #评论人
"publishUserId":9, #发布动态的人的id
"isParent":false, #是否为父节点,默认是否
"parentId":1001, #父节点id
"created":1568012791171
}
3、好友关系数据
由于圈子中会涉及的好友关系数据,虽然现在主线是开发圈子功能,但是也需要对于好友关系有所了解,在我们提供的Mongodb数据库中有一些mock数据。
好友关系结构:
package com.tanhua.dubbo.server.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.mapping.Document;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "tanhua_users")
public class Users implements java.io.Serializable{
private static final long serialVersionUID = 6003135946820874230L;
private ObjectId id;
private Long userId; //用户id
private Long friendId; //好友id
private Long date; //时间
}
在mock数据中,为每个用户构造了10个好友数据:
4、查询好友动态
查询好友动态与查询推荐动态显示的结构是一样的,只是其查询数据源不同:
4.1、基础代码
在my-tanhua-dubbo-interface中编写:
package com.tanhua.dubbo.server.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
import java.util.List;
/**
* 发布表,动态内容
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "quanzi_publish")
public class Publish implements java.io.Serializable {
private static final long serialVersionUID = 8732308321082804771L;
@Id
private ObjectId id; //主键id
private Long pid; //发布id
private Long userId; //发布用户id
private String text; //文字
private List<String> medias; //媒体数据,图片或小视频 url
private Integer seeType; // 谁可以看,1-公开,2-私密,3-部分可见,4-不给谁看
private List<Long> seeList; //部分可见的列表
private List<Long> notSeeList; //不给谁看的列表
private String longitude; //经度
private String latitude; //纬度
private String locationName; //位置名称
private Long created; //发布时间
}
package com.tanhua.dubbo.server.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
/**
* 相册表,用于存储自己发布的数据,每一个用户一张表进行存储
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "quanzi_album_{userId}")
public class Album implements java.io.Serializable {
private static final long serialVersionUID = 432183095092216817L;
@Id
private ObjectId id; //主键id
private ObjectId publishId; //发布id
private Long created; //发布时间
}
package com.tanhua.dubbo.server.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
/**
* 时间线表,用于存储发布的数据,每一个用户一张表进行存储
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "quanzi_time_line_{userId}")
public class TimeLine implements java.io.Serializable {
private static final long serialVersionUID = 9096178416317502524L;
@Id
private ObjectId id;
private Long userId; // 好友id
private ObjectId publishId; //发布id
private Long date; //发布的时间
}
package com.tanhua.dubbo.server.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
/**
* 评论表
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "quanzi_comment")
public class Comment implements java.io.Serializable{
private static final long serialVersionUID = -291788258125767614L;
@Id
private ObjectId id;
private ObjectId publishId; //发布id
private Integer commentType; //评论类型,1-点赞,2-评论,3-喜欢
private String content; //评论内容
private Long userId; //评论人
private Long publishUserId; //发布动态的用户id
private Boolean isParent = false; //是否为父节点,默认是否
private ObjectId parentId; // 父节点id
private Long created; //发表时间
}
4.2、dubbo服务
圈子的具体业务逻辑的实现需要在dubbo中完成,所以需要开发dubbo服务。
4.2.1、定义接口
在my-tanhua-dubbo-interface工程中:
package