面试场景题:设计微信朋友圈后端-从接口到数据库的实现

设计微信朋友圈后端:从接口到数据库的实现

微信朋友圈是一个典型的社交应用场景,涉及动态发布、查看、点赞、评论等功能,同时需要支持高并发和权限控制。在这篇博客中,我将从需求分析开始,逐步设计朋友圈的后端接口和数据库结构,并提供基于 Spring Boot 和 MySQL 的 Java 实现代码。


需求分析

微信朋友圈的核心功能包括:

  1. 发布动态:用户可以发布文字、图片、视频等内容。
  2. 查看动态:用户可以查看自己和好友的动态,按时间倒序排列。
  3. 评论与点赞:支持对动态进行评论和点赞。
  4. 权限控制:支持公开、仅好友可见、部分好友可见等设置。
  5. 高并发:需要支持大量用户同时操作。

基于这些需求,后端设计需要满足高并发、低延迟、可扩展性和数据一致性。


接口设计

以下是基于 RESTful 风格的核心 API 设计,使用 JSON 格式交互。

1. 发布动态

  • 接口POST /api/moments

  • 请求参数

    json 复制代码
    {
      "userId": "12345",
      "content": "今天天气很好",
      "media": [
        {"type": "image", "url": "http://example.com/img1.jpg"}
      ],
      "visibility": "friends",
      "visibleUserIds": ["67890"]
    }
  • 响应

    json 复制代码
    {
      "momentId": "10001",
      "createdAt": "2025-03-28T10:00:00Z"
    }

2. 获取朋友圈动态

  • 接口GET /api/moments?userId={userId}&page={page}&size={size}

  • 响应

    json 复制代码
    [
      {
        "momentId": "10001",
        "userId": "12345",
        "username": "张三",
        "content": "今天天气很好",
        "media": [{"type": "image", "url": "http://example.com/img1.jpg"}],
        "createdAt": "2025-03-28T10:00:00Z",
        "likes": 5,
        "comments": [
          {"userId": "67890", "username": "李四", "content": "确实不错"}
        ]
      }
    ]

3. 点赞动态

  • 接口POST /api/moments/{momentId}/like

  • 请求参数

    json 复制代码
    {
      "userId": "67890"
    }
  • 响应

    json 复制代码
    {
      "success": true,
      "likeCount": 6
    }

4. 评论动态

  • 接口POST /api/moments/{momentId}/comment

  • 请求参数

    json 复制代码
    {
      "userId": "67890",
      "content": "确实不错"
    }
  • 响应

    json 复制代码
    {
      "commentId": "20001",
      "createdAt": "2025-03-28T10:05:00Z"
    }

数据库设计

我选择 MySQL 作为主数据库,结合 Redis 优化高并发场景。以下是表结构设计:

表结构

用户表 (users)
sql 复制代码
CREATE TABLE users (
    user_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
动态表 (moments)
sql 复制代码
CREATE TABLE moments (
    moment_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    content TEXT,
    media JSON,
    visibility ENUM('public', 'friends', 'private', 'custom') DEFAULT 'friends',
    visible_user_ids JSON,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    like_count INT DEFAULT 0,
    FOREIGN KEY (user_id) REFERENCES users(user_id),
    INDEX idx_created_at (created_at)
);
点赞表 (moment_likes)
sql 复制代码
CREATE TABLE moment_likes (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    moment_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (moment_id) REFERENCES moments(moment_id),
    FOREIGN KEY (user_id) REFERENCES users(user_id),
    UNIQUE INDEX idx_moment_user (moment_id, user_id)
);
评论表 (moment_comments)
sql 复制代码
CREATE TABLE moment_comments (
    comment_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    moment_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    content TEXT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (moment_id) REFERENCES moments(moment_id),
    FOREIGN KEY (user_id) REFERENCES users(user_id),
    INDEX idx_moment_created (moment_id, created_at)
);

优化措施

  • 索引:为动态表添加时间索引,点赞表添加唯一索引防止重复点赞。
  • 分库分表 :按 user_idmoment_id 分片,支持水平扩展。
  • 缓存 :使用 Redis 存储热门动态的 like_count 和时间线数据。

Java 代码实现

以下是基于 Spring Boot 和 MyBatis 的实现,覆盖核心功能。

1. 依赖配置 (pom.xml)

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

2. 实体类

java 复制代码
public class Moment {
    private Long momentId;
    private Long userId;
    private String content;
    private String media; // JSON 字符串
    private String visibility;
    private String visibleUserIds; // JSON 字符串
    private Date createdAt;
    private Integer likeCount;
    // Getters and Setters
}

public class MomentLike {
    private Long id;
    private Long momentId;
    private Long userId;
    private Date createdAt;
    // Getters and Setters
}

public class MomentComment {
    private Long commentId;
    private Long momentId;
    private Long userId;
    private String content;
    private Date createdAt;
    // Getters and Setters
}

3. Mapper 接口

java 复制代码
@Mapper
public interface MomentMapper {
    @Insert("INSERT INTO moments(user_id, content, media, visibility, visible_user_ids) " +
            "VALUES(#{userId}, #{content}, #{media}, #{visibility}, #{visibleUserIds})")
    @Options(useGeneratedKeys = true, keyProperty = "momentId")
    void insert(Moment moment);

    @Select("SELECT m.*, u.username FROM moments m JOIN users u ON m.user_id = u.user_id " +
            "WHERE m.created_at <= #{cursor} ORDER BY m.created_at DESC LIMIT #{size}")
    List<Moment> findMomentsByCursor(@Param("cursor") Date cursor, @Param("size") int size);
}

@Mapper
public interface MomentLikeMapper {
    @Insert("INSERT INTO moment_likes(moment_id, user_id) VALUES(#{momentId}, #{userId})")
    void insert(MomentLike like);

    @Update("UPDATE moments SET like_count = like_count + 1 WHERE moment_id = #{momentId}")
    void incrementLikeCount(Long momentId);
}

@Mapper
public interface MomentCommentMapper {
    @Insert("INSERT INTO moment_comments(moment_id, user_id, content) " +
            "VALUES(#{momentId}, #{userId}, #{content})")
    @Options(useGeneratedKeys = true, keyProperty = "commentId")
    void insert(MomentComment comment);
}

4. Service 层

java 复制代码
@Service
public class MomentService {
    @Autowired
    private MomentMapper momentMapper;
    @Autowired
    private MomentLikeMapper likeMapper;
    @Autowired
    private MomentCommentMapper commentMapper;

    @Transactional
    public Long createMoment(Moment moment) {
        momentMapper.insert(moment);
        return moment.getMomentId();
    }

    public List<Moment> getMoments(Long userId, int page, int size) {
        Date cursor = new Date();
        return momentMapper.findMomentsByCursor(cursor, size);
    }

    @Transactional
    public void likeMoment(Long momentId, Long userId) {
        MomentLike like = new MomentLike();
        like.setMomentId(momentId);
        like.setUserId(userId);
        likeMapper.insert(like);
        likeMapper.incrementLikeCount(momentId);
    }

    @Transactional
    public Long commentMoment(Long momentId, Long userId, String content) {
        MomentComment comment = new MomentComment();
        comment.setMomentId(momentId);
        comment.setUserId(userId);
        comment.setContent(content);
        commentMapper.insert(comment);
        return comment.getCommentId();
    }
}

5. Controller 层

java 复制代码
@RestController
@RequestMapping("/api/moments")
public class MomentController {
    @Autowired
    private MomentService momentService;

    @PostMapping
    public ResponseEntity<Map<String, Object>> createMoment(@RequestBody Moment moment) {
        Long momentId = momentService.createMoment(moment);
        Map<String, Object> response = new HashMap<>();
        response.put("momentId", momentId);
        response.put("createdAt", new Date());
        return ResponseEntity.ok(response);
    }

    @GetMapping
    public ResponseEntity<List<Moment>> getMoments(
            @RequestParam Long userId,
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size) {
        List<Moment> moments = momentService.getMoments(userId, page, size);
        return ResponseEntity.ok(moments);
    }

    @PostMapping("/{momentId}/like")
    public ResponseEntity<Map<String, Object>> likeMoment(
            @PathVariable Long momentId,
            @RequestBody Map<String, Long> request) {
        Long userId = request.get("userId");
        momentService.likeMoment(momentId, userId);
        Map<String, Object> response = new HashMap<>();
        response.put("success", true);
        return ResponseEntity.ok(response);
    }

    @PostMapping("/{momentId}/comment")
    public ResponseEntity<Map<String, Object>> commentMoment(
            @PathVariable Long momentId,
            @RequestBody MomentComment comment) {
        Long commentId = momentService.commentMoment(momentId, comment.getUserId(), comment.getContent());
        Map<String, Object> response = new HashMap<>();
        response.put("commentId", commentId);
        response.put("createdAt", new Date());
        return ResponseEntity.ok(response);
    }
}

系统架构优化

  1. 高并发
    • 使用消息队列(如 Kafka)异步处理点赞和评论。
    • 动态时间线采用"读扩散"模型,聚合好友动态到 Redis。
  2. 权限控制
    • 在 Service 层校验 visibilityvisible_user_ids
  3. 扩展性
    • 媒体文件存储在分布式文件系统(如 S3),URL 存入数据库。
    • 数据库按 user_id 分库分表。

总结

通过这篇博客,我们从需求出发,设计了微信朋友圈的接口和数据库,并用 Java 实现了核心功能。代码虽然简化(未完全实现权限和缓存),但展示了后端开发的基本思路。实际生产中,还需加入异常处理、分布式锁、缓存一致性等优化。

相关推荐
招风的黑耳1 天前
智慧养老项目:当SpringBoot遇到硬件,如何优雅地处理异常与状态管理?
java·spring boot·后端
回家路上绕了弯1 天前
分布式锁原理深度解析:从理论到实践
分布式·后端
磊磊磊磊磊1 天前
用AI做了个排版工具,分享一下如何高效省钱地用AI!
前端·后端·react.js
hgz07101 天前
Spring Boot Starter机制
java·spring boot·后端
daxiang120922051 天前
Spring boot服务启动报错 java.lang.StackOverflowError 原因分析
java·spring boot·后端
我家领养了个白胖胖1 天前
极简集成大模型!Spring AI Alibaba ChatClient 快速上手指南
java·后端·ai编程
一代明君Kevin学长1 天前
快速自定义一个带进度监控的文件资源类
java·前端·后端·python·文件上传·文件服务·文件流
aiopencode1 天前
上架 iOS 应用到底在做什么?从准备工作到上架的流程
后端
哈哈老师啊1 天前
Springboot简单二手车网站qs5ed(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
JIngJaneIL1 天前
基于Java+ vue图书管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端