本文目录导读:

我来为您设计一个完整的Java社交系统案例,包含核心功能模块和实现代码。
项目结构
social-system/
├── pom.xml
├── src/main/java/com/social/
│ ├── SocialApplication.java
│ ├── config/
│ │ ├── SecurityConfig.java
│ │ └── RedisConfig.java
│ ├── controller/
│ │ ├── UserController.java
│ │ ├── PostController.java
│ │ ├── FriendController.java
│ │ └── MessageController.java
│ ├── service/
│ │ ├── impl/
│ │ │ ├── UserServiceImpl.java
│ │ │ ├── PostServiceImpl.java
│ │ │ ├── FriendServiceImpl.java
│ │ │ └── MessageServiceImpl.java
│ │ └── ...
│ ├── mapper/
│ ├── entity/
│ ├── dto/
│ └── util/
└── src/main/resources/
├── application.yml
└── mapper/
Maven配置 (pom.xml)
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
</parent>
<groupId>com.social</groupId>
<artifactId>social-system</artifactId>
<version>1.0.0</version>
<properties>
<java.version>11</java.version>
<jjwt.version>0.11.5</jjwt.version>
</properties>
<dependencies>
<!-- Spring Boot Starters -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- MyBatis Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- FastJson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
</dependencies>
</project>
实体类设计
User.java
package com.social.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password;
private String nickname;
private String avatar;
private String email;
private String phone;
private String bio; // 个人简介
private Integer gender; // 0:未知 1:男 2:女
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
private Integer deleted; // 逻辑删除
private Integer status; // 账号状态
}
Post.java
package com.social.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Data
@TableName("post")
public class Post {
@TableId(type = IdType.AUTO)
private Long id;
private Long userId;
private String content;
private String images; // JSON存储多张图片
private String location;
@TableField(exist = false)
private User user; // 发布者信息
@TableField(exist = false)
private Integer likeCount; // 点赞数
@TableField(exist = false)
private Integer commentCount; // 评论数
@TableField(exist = false)
private Boolean isLiked; // 当前用户是否点赞
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
private Integer deleted;
private Integer status;
}
Friend.java
package com.social.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("friend")
public class Friend {
@TableId(type = IdType.AUTO)
private Long id;
private Long userId;
private Long friendId;
private Integer status; // 0:待确认 1:已通过 2:已拒绝
private String remark; // 好友备注
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
控制器层
UserController.java
package com.social.controller;
import com.social.common.Result;
import com.social.dto.LoginDTO;
import com.social.dto.RegisterDTO;
import com.social.dto.UpdateUserDTO;
import com.social.entity.User;
import com.social.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 用户注册
*/
@PostMapping("/register")
public Result register(@Valid @RequestBody RegisterDTO registerDTO) {
return userService.register(registerDTO);
}
/**
* 用户登录
*/
@PostMapping("/login")
public Result login(@Valid @RequestBody LoginDTO loginDTO) {
return userService.login(loginDTO);
}
/**
* 获取用户信息
*/
@GetMapping("/{id}")
public Result getById(@PathVariable Long id) {
return userService.getUserInfo(id);
}
/**
* 更新用户信息
*/
@PutMapping("/{id}")
public Result updateProfile(@PathVariable Long id,
@RequestBody UpdateUserDTO updateUserDTO) {
return userService.updateUser(id, updateUserDTO);
}
/**
* 搜索用户
*/
@GetMapping("/search")
public Result search(String keyword,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
return userService.searchUsers(keyword, page, size);
}
}
PostController.java
package com.social.controller;
import com.social.common.Result;
import com.social.dto.CreatePostDTO;
import com.social.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/post")
public class PostController {
@Autowired
private PostService postService;
/**
* 创建帖子
*/
@PostMapping
public Result createPost(@RequestBody CreatePostDTO createPostDTO) {
return postService.createPost(createPostDTO);
}
/**
* 删除帖子
*/
@DeleteMapping("/{id}")
public Result deletePost(@PathVariable Long id) {
return postService.deletePost(id);
}
/**
* 获取帖子详情
*/
@GetMapping("/{id}")
public Result getPost(@PathVariable Long id) {
return postService.getPost(id);
}
/**
* 获取时间线(关注用户的帖子)
*/
@GetMapping("/timeline")
public Result getTimeline(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
return postService.getTimeline(page, size);
}
/**
* 获取用户发布的帖子
*/
@GetMapping("/user/{userId}")
public Result getUserPosts(@PathVariable Long userId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
return postService.getUserPosts(userId, page, size);
}
/**
* 点赞/取消点赞
*/
@PostMapping("/{id}/like")
public Result like(@PathVariable Long id) {
return postService.likePost(id);
}
/**
* 评论
*/
@PostMapping("/{id}/comment")
public Result comment(@PathVariable Long id, @RequestParam String content) {
return postService.commentPost(id, content);
}
}
服务层实现
UserServiceImpl.java
package com.social.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.social.common.Result;
import com.social.dto.LoginDTO;
import com.social.dto.RegisterDTO;
import com.social.dto.UpdateUserDTO;
import com.social.entity.User;
import com.social.exception.BusinessException;
import com.social.mapper.UserMapper;
import com.social.service.UserService;
import com.social.util.JwtUtil;
import com.social.util.RedisUtil;
import com.social.vo.LoginVO;
import com.social.vo.UserVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private JwtUtil jwtUtil;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public Result register(RegisterDTO registerDTO) {
// 检查用户名是否已存在
User existingUser = userMapper.selectOne(
new LambdaQueryWrapper<User>()
.eq(User::getUsername, registerDTO.getUsername())
);
if (existingUser != null) {
throw new BusinessException("用户名已存在");
}
// 创建新用户
User user = new User();
BeanUtils.copyProperties(registerDTO, user);
user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
user.setNickname(registerDTO.getUsername());
user.setAvatar("default_avatar.png");
userMapper.insert(user);
return Result.success("注册成功", user.getId());
}
@Override
public Result login(LoginDTO loginDTO) {
// 查询用户
User user = userMapper.selectOne(
new LambdaQueryWrapper<User>()
.eq(User::getUsername, loginDTO.getUsername())
);
if (user == null || !passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
throw new BusinessException("用户名或密码错误");
}
// 生成JWT Token
String token = jwtUtil.generateToken(user.getId(), user.getUsername());
// 存储到Redis,设置7天有效期
String redisKey = "token:" + user.getId();
redisTemplate.opsForValue().set(redisKey, token, 7, TimeUnit.DAYS);
// 构建返回数据
LoginVO loginVO = new LoginVO();
loginVO.setToken(token);
UserVO userVO = new UserVO();
BeanUtils.copyProperties(user, userVO);
loginVO.setUser(userVO);
return Result.success("登录成功", loginVO);
}
@Override
public Result getUserInfo(Long id) {
User user = userMapper.selectById(id);
if (user == null) {
throw new BusinessException("用户不存在");
}
UserVO userVO = new UserVO();
BeanUtils.copyProperties(user, userVO);
// 获取关注数和粉丝数
Integer followCount = userMapper.getFollowCount(id);
Integer fansCount = userMapper.getFansCount(id);
Map<String, Object> data = new HashMap<>();
data.put("userInfo", userVO);
data.put("followCount", followCount);
data.put("fansCount", fansCount);
return Result.success(data);
}
@Override
public Result updateUser(Long id, UpdateUserDTO updateUserDTO) {
User user = userMapper.selectById(id);
if (user == null) {
throw new BusinessException("用户不存在");
}
// 更新用户信息
if (StringUtils.hasText(updateUserDTO.getNickname())) {
user.setNickname(updateUserDTO.getNickname());
}
if (StringUtils.hasText(updateUserDTO.getAvatar())) {
user.setAvatar(updateUserDTO.getAvatar());
}
if (updateUserDTO.getGender() != null) {
user.setGender(updateUserDTO.getGender());
}
if (StringUtils.hasText(updateUserDTO.getBio())) {
user.setBio(updateUserDTO.getBio());
}
userMapper.updateById(user);
UserVO userVO = new UserVO();
BeanUtils.copyProperties(user, userVO);
return Result.success("更新成功", userVO);
}
@Override
public Result searchUsers(String keyword, int page, int size) {
IPage<User> userPage = null;
if (StringUtils.hasText(keyword)) {
userPage = userMapper.selectPage(
new Page<>(page, size),
new LambdaQueryWrapper<User>()
.like(User::getUsername, keyword)
.or()
.like(User::getNickname, keyword)
);
} else {
userPage = userMapper.selectPage(new Page<>(page, size), null);
}
return Result.success(userPage);
}
}
PostServiceImpl.java
package com.social.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.social.common.Result;
import com.social.dto.CreatePostDTO;
import com.social.entity.Post;
import com.social.entity.User;
import com.social.exception.BusinessException;
import com.social.mapper.PostMapper;
import com.social.mapper.UserMapper;
import com.social.service.PostService;
import com.social.util.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service
public class PostServiceImpl implements PostService {
@Autowired
private PostMapper postMapper;
@Autowired
private UserMapper userMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public Result createPost(CreatePostDTO createPostDTO) {
Post post = new Post();
BeanUtils.copyProperties(createPostDTO, post);
postMapper.insert(post);
// 将帖子ID加入用户的时间线缓存
String timelineKey = "timeline:user:" + post.getUserId();
redisTemplate.opsForList().leftPush(timelineKey, post.getId());
return Result.success("发布成功", post.getId());
}
@Override
public Result deletePost(Long id) {
Post post = postMapper.selectById(id);
if (post == null) {
throw new BusinessException("帖子不存在");
}
// 逻辑删除
post.setDeleted(1);
postMapper.updateById(post);
return Result.success("删除成功");
}
@Override
public Result getPost(Long id) {
// 尝试从缓存获取
String cacheKey = "post:" + id;
Object cached = redisTemplate.opsForValue().get(cacheKey);
if (cached != null) {
return Result.success(cached);
}
Post post = postMapper.selectById(id);
if (post == null) {
throw new BusinessException("帖子不存在");
}
// 填充用户信息
User user = userMapper.selectById(post.getUserId());
post.setUser(user);
// 获取点赞数和评论数
post.setLikeCount(getLikeCount(id));
post.setCommentCount(getCommentCount(id));
// 存入缓存,5分钟过期
redisTemplate.opsForValue().set(cacheKey, post, 5, TimeUnit.MINUTES);
return Result.success(post);
}
@Override
public Result getTimeline(int page, int size) {
// 获取当前登录用户ID(从上下文获取)
Long currentUserId = SecurityUtil.getCurrentUserId();
// 获取关注用户的帖子(这里简化处理,使用Redis缓存实现)
String timelineKey = "timeline:user:" + currentUserId;
// 实际应用中可从数据库查询,这里简化实现
IPage<Post> postPage = postMapper.selectPage(
new Page<>(page, size),
new LambdaQueryWrapper<Post>()
.eq(Post::getDeleted, 0)
.orderByDesc(Post::getCreateTime)
);
// 填充用户信息
List<Post> records = postPage.getRecords();
records.forEach(post -> {
User user = userMapper.selectById(post.getUserId());
post.setUser(user);
});
return Result.success(postPage);
}
@Override
public Result getUserPosts(Long userId, int page, int size) {
IPage<Post> postPage = postMapper.selectPage(
new Page<>(page, size),
new LambdaQueryWrapper<Post>()
.eq(Post::getUserId, userId)
.eq(Post::getDeleted, 0)
.orderByDesc(Post::getCreateTime)
);
return Result.success(postPage);
}
@Override
public Result likePost(Long postId) {
Long currentUserId = SecurityUtil.getCurrentUserId();
String likeKey = "post:like:" + postId;
Boolean isLiked = redisTemplate.opsForSet().isMember(likeKey, currentUserId);
if (Boolean.TRUE.equals(isLiked)) {
// 取消点赞
redisTemplate.opsForSet().remove(likeKey, currentUserId);
return Result.success("已取消点赞");
} else {
// 点赞
redisTemplate.opsForSet().add(likeKey, currentUserId);
return Result.success("点赞成功");
}
}
@Override
public Result commentPost(Long postId, String content) {
Long currentUserId = SecurityUtil.getCurrentUserId();
// 创建评论记录
Comment comment = new Comment();
comment.setPostId(postId);
comment.setUserId(currentUserId);
comment.setContent(content);
commentMapper.insert(comment);
// 更新评论数缓存
String commentCountKey = "post:comment:count:" + postId;
redisTemplate.opsForValue().increment(commentCountKey);
return Result.success("评论成功", comment.getId());
}
private int getLikeCount(Long postId) {
String likeKey = "post:like:" + postId;
return redisTemplate.opsForSet().size(likeKey).intValue();
}
private int getCommentCount(Long postId) {
String commentCountKey = "post:comment:count:" + postId;
Integer count = (Integer) redisTemplate.opsForValue().get(commentCountKey);
return count == null ? 0 : count;
}
}
安全配置
SecurityConfig.java
package com.social.config;
import com.social.security.JwtAuthenticationFilter;
import com.social.security.JwtUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
private JwtUserDetailsService jwtUserDetailsService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/user/register", "/api/user/login").permitAll()
.antMatchers("/swagger-ui/**", "/api-docs/**").permitAll()
.anyRequest().authenticated()
.and()
.userDetailsService(jwtUserDetailsService);
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
}
JWT工具类
JwtUtil.java
package com.social.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
private Key key;
@PostConstruct
public void init() {
this.key = Keys.hmacShaKeyFor(secret.getBytes());
}
/**
* 生成Token
*/
public String generateToken(Long userId, String username) {
Map<String, Object> claims = new HashMap<>();
claims.put("userId", userId);
claims.put("username", username);
Date now = new Date();
Date expiryDate = new Date(now.getTime() + expiration);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(key, SignatureAlgorithm.HS256)
.compact();
}
/**
* 解析Token
*/
public Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
}
/**
* 验证Token是否有效
*/
public boolean validateToken(String token) {
try {
Jwts.parser()
.setSigningKey(key)
.build()
.parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 从Token获取用户ID
*/
public Long getUserIdFromToken(String token) {
Claims claims = parseToken(token);
return claims.get("userId", Long.class);
}
}
统一返回结果
Result.java
package com.social.common;
import lombok.Data;
@Data
public class Result {
private Integer code;
private String message;
private Object data;
public static Result success(Object data) {
Result result = new Result();
result.setCode(200);
result.setMessage("操作成功");
result.setData(data);
return result;
}
public static Result success(String message, Object data) {
Result result = new Result();
result.setCode(200);
result.setMessage(message);
result.setData(data);
return result;
}
public static Result error(Integer code, String message) {
Result result = new Result();
result.setCode(code);
result.setMessage(message);
return result;
}
}
配置文件
application.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/social_system?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
host: localhost
port: 6379
password:
database: 0
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
jwt:
secret: your-secret-key-here-at-least-256-bits-long
expiration: 604800000 # 7天
数据库脚本
-- 用户表 CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL, `password` varchar(255) NOT NULL, `nickname` varchar(50) DEFAULT NULL, `avatar` varchar(255) DEFAULT NULL, `email` varchar(100) DEFAULT NULL, `phone` varchar(20) DEFAULT NULL, `bio` varchar(500) DEFAULT NULL, `gender` tinyint DEFAULT '0', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `deleted` tinyint DEFAULT '0', `status` tinyint DEFAULT '1', PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 帖子表 CREATE TABLE `post` ( `id` bigint NOT NULL AUTO_INCREMENT, `user_id` bigint NOT NULL, `content` text, `images` text, `location` varchar(200) DEFAULT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `deleted` tinyint DEFAULT '0', `status` tinyint DEFAULT '1', PRIMARY KEY (`id`), KEY `idx_user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 好友关系表 CREATE TABLE `friend` ( `id` bigint NOT NULL AUTO_INCREMENT, `user_id` bigint NOT NULL, `friend_id` bigint NOT NULL, `status` tinyint DEFAULT '0', `remark` varchar(100) DEFAULT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_user_friend` (`user_id`, `friend_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 评论表 CREATE TABLE `comment` ( `id` bigint NOT NULL AUTO_INCREMENT, `post_id` bigint NOT NULL, `user_id` bigint NOT NULL, `content` varchar(500) NOT NULL, `parent_id` bigint DEFAULT '0', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `deleted` tinyint DEFAULT '0', PRIMARY KEY (`id`), KEY `idx_post_id` (`post_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 点赞表 CREATE TABLE `post_like` ( `id` bigint NOT NULL AUTO_INCREMENT, `post_id` bigint NOT NULL, `user_id` bigint NOT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_post_user` (`post_id`, `user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 私信表 CREATE TABLE `message` ( `id` bigint NOT NULL AUTO_INCREMENT, `from_user_id` bigint NOT NULL, `to_user_id` bigint NOT NULL, `content` text NOT NULL, `message_type` tinyint DEFAULT '1', `is_read` tinyint DEFAULT '0', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_from_to` (`from_user_id`, `to_user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
核心功能演示
实际使用示例
@RestController
@RequestMapping("/api/demo")
public class DemoController {
@Autowired
private PostService postService;
@Autowired
private FriendService friendService;
/**
* 获取好友最新动态
*/
@GetMapping("/friends/feed")
public Result getFriendsFeed() {
Long userId = SecurityUtil.getCurrentUserId();
// 获取好友列表
List<Long> friendIds = friendService.getFriendIds(userId);
// 获取所有好友的帖子(简化实现)
List<Post> posts = postService.getPostsByUserIds(friendIds);
return Result.success(posts);
}
}
这个Java社交系统案例包含了:
- 用户系统:注册、登录、JWT认证
- 社交功能:发帖、点赞、评论
- 好友系统:添加好友、好友动态
- 缓存优化:Redis缓存热门数据
- 安全处理:Spring Security + JWT
可以根据实际需求扩展更多功能,如消息推送、群组、图片上传等。