欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > Java项目——校园社交网络平台的设计与实现

Java项目——校园社交网络平台的设计与实现

2025/4/22 20:07:29 来源:https://blog.csdn.net/exlink2012/article/details/147308607  浏览:    关键词:Java项目——校园社交网络平台的设计与实现

一、项目背景

随着移动互联网的发展,校园社交网络平台成为高校师生信息交流、资源共享和兴趣互动的重要工具。本文以Java为主要开发语言,介绍一个校园社交网络平台的设计与实现过程,涵盖系统架构、核心功能、技术选型及关键实现细节。

二、需求分析

1. 用户需求

  • 学生、教师注册与登录
  • 个人信息管理与展示
  • 好友添加与分组
  • 动态发布与评论
  • 消息通知与私信
  • 社团/兴趣小组管理
  • 活动报名与签到

2. 系统需求

  • 支持高并发访问
  • 数据安全与隐私保护
  • 良好的可扩展性和可维护性

三、系统架构设计

1. 总体架构

采用B/S(浏览器/服务器)架构,前端使用React,后端采用Spring Boot框架,数据库选用MySQL,文件存储采用阿里云OSS或本地服务器。

[客户端] ←→ [Nginx负载均衡] ←→ [Spring Boot服务集群] ←→ [MySQL/Redis/OSS]

2. 主要技术栈

  • 后端:Java 17、Spring Boot、Spring Security、MyBatis Plus、Redis、OSS SDK
  • 前端:React、Element UI、Axios
  • 数据库:MySQL 8.x
  • 其他:JWT鉴权、WebSocket实时通信、Docker容器部署

四、核心功能模块

1. 用户与权限管理

  • 支持学生、教师多角色注册与登录
  • 基于JWT的Token认证机制
  • 用户信息完善与隐私设置

2. 好友与社交关系

  • 好友申请、同意、分组管理
  • 黑名单与举报功能

3. 动态与互动

  • 发布图文/多媒体动态
  • 点赞、评论、转发
  • 热门话题与内容推荐

4. 消息与通知

  • 私信聊天(WebSocket实现)
  • 系统通知、活动提醒

5. 社团与活动

  • 社团/兴趣小组创建与管理
  • 活动发布、报名、签到与统计

6. 后台管理

  • 用户、内容、社团审核
  • 数据统计与系统日志

五、数据库设计

采用E-R建模,主要表结构如下:

  • 用户表(user)
  • 好友关系表(friend)
  • 动态内容表(post)
  • 评论表(comment)
  • 消息表(message)
  • 社团表(club)
  • 活动表(activity)

六、关键实现细节

1. JWT鉴权流程

  1. 用户登录成功后生成JWT Token
  2. 前端每次请求携带Token
  3. 后端拦截器验证Token有效性

2. WebSocket实时通信

  • 基于Spring Boot内置WebSocket支持
  • 实现私信、系统通知的实时推送

3. 文件上传与多媒体处理

  • 采用阿里云OSS存储图片、视频等资源
  • 后端提供统一上传接口,支持分片上传

七、系统部署与运维

  • 使用Docker容器化部署后端服务和数据库
  • Nginx实现负载均衡和静态资源代理
  • 日志采集与监控(ELK、Prometheus)

八、总结与展望

本文介绍了基于Java的校园社交网络平台的设计与实现思路。未来可进一步集成AI推荐算法、移动端小程序、校园一卡通等功能,持续提升用户体验和系统智能化水平。

源代码:

Directory Content Summary

Source Directory: ./campus-social-network

Directory Structure

campus-social-network/pom.xmlREADME.mddb/schema.sqlfrontend/package.jsonsrc/api.jsApp.jsmodules/ActivityModule.jsClubModule.jsFriendModule.jsMessageModule.jsPostModule.jsUserModule.jssrc/main/java/com/example/campus/CampusSocialNetworkApplication.javacontroller/ActivityController.javaAuthController.javaClubController.javaFriendController.javaMessageController.javaPostController.javaUserController.javadto/AddFriendRequest.javaCreateActivityRequest.javaCreateClubRequest.javaCreateCommentRequest.javaCreatePostRequest.javaJoinClubRequest.javaLoginRequest.javaMoveFriendRequest.javaRegisterRequest.javaSendMessageRequest.javaUpdateProfileRequest.javaentity/Activity.javaActivitySignup.javaClub.javaClubMember.javaComment.javaFriend.javaMessage.javaPost.javaUser.javarepository/ActivityRepository.javaActivitySignupRepository.javaClubMemberRepository.javaClubRepository.javaCommentRepository.javaFriendRepository.javaMessageRepository.javaPostRepository.javaUserRepository.javaservice/ActivityService.javaClubService.javaFriendService.javaMessageService.javaPostService.javaUserService.javaresources/application.ymlschema.sql

File Contents

pom.xml

<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><groupId>com.example</groupId><artifactId>campus-social-network</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>Campus Social Network</name><properties><java.version>1.8</java.version><spring-boot.version>2.7.5</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

README.md

# Campus Social Network基于Spring Boot的校园社交网络平台示例项目。## 功能简介
- 学生、教师注册与登录
- 用户信息管理
- 后端接口示例## 目录结构campus-social-network/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/campus/
│   │   │       ├── CampusSocialNetworkApplication.java
│   │   │       ├── controller/
│   │   │       │   └── AuthController.java
│   │   │       ├── entity/
│   │   │       │   └── User.java
│   │   │       ├── repository/
│   │   │       │   └── UserRepository.java
│   │   │       ├── service/
│   │   │       │   └── UserService.java
│   │   │       └── dto/
│   │   │           ├── RegisterRequest.java
│   │   │           └── LoginRequest.java
│   │   └── resources/
│   │       ├── application.yml
│   │       └── schema.sql
├── pom.xml
└── README.md

快速开始

  1. 创建数据库 campus_social_network,导入 src/main/resources/schema.sql
  2. 修改 application.yml 数据库配置
  3. 使用IDEA或Maven命令行运行项目

接口示例

  • POST /api/auth/register 注册
  • POST /api/auth/login 登录

### db\schema.sql```sql
-- 用户表
CREATE TABLE user (id BIGINT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(50) NOT NULL UNIQUE,password VARCHAR(100) NOT NULL,role VARCHAR(20),email VARCHAR(100),real_name VARCHAR(50),created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);-- 好友表
CREATE TABLE friend (id BIGINT PRIMARY KEY AUTO_INCREMENT,user_id BIGINT NOT NULL,friend_id BIGINT NOT NULL,group_name VARCHAR(50),created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);-- 帖子表
CREATE TABLE post (id BIGINT PRIMARY KEY AUTO_INCREMENT,user_id BIGINT NOT NULL,content VARCHAR(1000) NOT NULL,image_url VARCHAR(255),created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);-- 评论表
CREATE TABLE comment (id BIGINT PRIMARY KEY AUTO_INCREMENT,post_id BIGINT NOT NULL,user_id BIGINT NOT NULL,content VARCHAR(1000) NOT NULL,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);-- 消息表
CREATE TABLE message (id BIGINT PRIMARY KEY AUTO_INCREMENT,sender_id BIGINT NOT NULL,receiver_id BIGINT NOT NULL,content VARCHAR(1000) NOT NULL,is_read BOOLEAN DEFAULT FALSE,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);-- 社团表
CREATE TABLE club (id BIGINT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100) NOT NULL UNIQUE,description VARCHAR(255),creator_id BIGINT,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);-- 社团成员表
CREATE TABLE club_member (id BIGINT PRIMARY KEY AUTO_INCREMENT,club_id BIGINT NOT NULL,user_id BIGINT NOT NULL,role VARCHAR(20) NOT NULL,UNIQUE(club_id, user_id)
);-- 活动表
CREATE TABLE activity (id BIGINT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(100) NOT NULL,description VARCHAR(255),club_id BIGINT,start_time TIMESTAMP,end_time TIMESTAMP,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);-- 活动报名表
CREATE TABLE activity_signup (id BIGINT PRIMARY KEY AUTO_INCREMENT,activity_id BIGINT NOT NULL,user_id BIGINT NOT NULL,checked_in BOOLEAN DEFAULT FALSE,signup_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,checkin_time TIMESTAMP,UNIQUE(activity_id, user_id)
);

frontend\package.json

{"name": "campus-social-network-frontend","version": "1.0.0","private": true,"dependencies": {"react": "^18.2.0","react-dom": "^18.2.0","react-router-dom": "^6.22.0","axios": "^1.6.0","antd": "^5.13.0"},"scripts": {"start": "webpack serve --mode development --open","build": "webpack --mode production"}
}

frontend\src\api.js

import axios from 'axios';const api = axios.create({baseURL: '/api',
});// 请求拦截器
api.interceptors.request.use(config => {const token = localStorage.getItem('token');if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;
});// 响应拦截器
api.interceptors.response.use(response => response,error => {if (error.response && error.response.status === 401) {// 未登录或 token 过期localStorage.removeItem('token');window.location.href = '/user/login';}return Promise.reject(error);}
);// 用户模块 API
export const userApi = {register: (data) => api.post('/user/register', data),login: (data) => api.post('/user/login', data),getProfile: (userId) => api.get(`/user/${userId}`),updateProfile: (userId, data) => api.put(`/user/${userId}`, data),
};// 好友模块 API
export const friendApi = {addFriend: (data) => api.post('/friend/add', data),listFriends: (userId) => api.get(`/friend/${userId}`),moveFriend: (data) => api.put('/friend/move', data),
};// 动态模块 API
export const postApi = {createPost: (data) => api.post('/post/create', data),listPosts: (userId) => api.get(`/post/user/${userId}`),createComment: (data) => api.post('/post/comment', data),
};// 消息模块 API
export const messageApi = {sendMessage: (senderId, data) => api.post(`/message/${senderId}/send`, data),listReceivedMessages: (receiverId) => api.get(`/message/received/${receiverId}`),listConversation: (userId1, userId2) => api.get(`/message/conversation/${userId1}/${userId2}`),markAsRead: (messageId) => api.put(`/message/read/${messageId}`),
};// 社团模块 API
export const clubApi = {createClub: (data) => api.post('/club/create', data),listClubs: () => api.get('/club/list'),listMembers: (clubId) => api.get(`/club/${clubId}/members`),joinClub: (data) => api.post('/club/join', data),listClubsByUser: (userId) => api.get(`/club/user/${userId}`),
};// 活动模块 API
export const activityApi = {createActivity: (data) => api.post('/activity/create', data),listAllActivities: () => api.get('/activity/list'),listActivitiesByClub: (clubId) => api.get(`/activity/club/${clubId}`),signup: (activityId, userId) => api.post(`/activity/${activityId}/signup/${userId}`),listSignups: (activityId) => api.get(`/activity/${activityId}/signups`),checkin: (activityId, userId) => api.put(`/activity/${activityId}/checkin/${userId}`),
};export default api;

frontend\src\App.js

import React from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import UserModule from './modules/UserModule';
import FriendModule from './modules/FriendModule';
import PostModule from './modules/PostModule';
import MessageModule from './modules/MessageModule';
import ClubModule from './modules/ClubModule';
import ActivityModule from './modules/ActivityModule';
import 'antd/dist/reset.css';
import { Layout, Menu } from 'antd';const { Header, Content } = Layout;export default function App() {return (<Router><Layout style={{ minHeight: '100vh' }}><Header><Menu theme="dark" mode="horizontal" defaultSelectedKeys={['user']}><Menu.Item key="user"><a href="/user">用户</a></Menu.Item><Menu.Item key="friend"><a href="/friend">好友</a></Menu.Item><Menu.Item key="post"><a href="/post">动态</a></Menu.Item><Menu.Item key="message"><a href="/message">消息</a></Menu.Item><Menu.Item key="club"><a href="/club">社团</a></Menu.Item><Menu.Item key="activity"><a href="/activity">活动</a></Menu.Item></Menu></Header><Content style={{ padding: 24 }}><Routes><Route path="/user/*" element={<UserModule />} /><Route path="/friend/*" element={<FriendModule />} /><Route path="/post/*" element={<PostModule />} /><Route path="/message/*" element={<MessageModule />} /><Route path="/club/*" element={<ClubModule />} /><Route path="/activity/*" element={<ActivityModule />} /><Route path="*" element={<Navigate to="/user" />} /></Routes></Content></Layout></Router>);
}

frontend\src\modules\ActivityModule.js

import React, { useState, useEffect } from 'react';
import { Card, List, Avatar, Button, Input, Form, Modal, message, Tabs, Typography, Divider, Tag, DatePicker, Space } from 'antd';
import { CalendarOutlined, UserOutlined, PlusOutlined, CheckOutlined, TeamOutlined, ScheduleOutlined } from '@ant-design/icons';
import { activityApi, clubApi } from '../api';
import moment from 'moment';const { TabPane } = Tabs;
const { Title, Text, Paragraph } = Typography;
const { TextArea } = Input;
const { RangePicker } = DatePicker;export default function ActivityModule() {const [activities, setActivities] = useState([]);const [clubActivities, setClubActivities] = useState([]);const [loading, setLoading] = useState(true);const [createModalVisible, setCreateModalVisible] = useState(false);const [signupModalVisible, setSignupModalVisible] = useState(false);const [checkinModalVisible, setCheckinModalVisible] = useState(false);const [selectedActivity, setSelectedActivity] = useState(null);const [signups, setSignups] = useState([]);const [signupsModalVisible, setSignupsModalVisible] = useState(false);const [clubs, setClubs] = useState([]);const [myClubs, setMyClubs] = useState([]);const [createForm] = Form.useForm();const userId = localStorage.getItem('userId');// 获取活动列表const fetchActivities = async () => {try {setLoading(true);const response = await activityApi.listAllActivities();setActivities(response.data || []);} catch (error) {message.error('获取活动列表失败');} finally {setLoading(false);}};// 获取我的社团const fetchMyClubs = async () => {try {const response = await clubApi.listClubsByUser(userId);setMyClubs(response.data || []);// 获取社团列表const clubsResponse = await clubApi.listClubs();setClubs(clubsResponse.data || []);// 获取我的社团的活动const clubIds = response.data.map(item => item.clubId);const activitiesPromises = clubIds.map(clubId => activityApi.listActivitiesByClub(clubId));const activitiesResponses = await Promise.all(activitiesPromises);const allClubActivities = activitiesResponses.flatMap(res => res.data || []);setClubActivities(allClubActivities);} catch (error) {message.error('获取社团活动失败');}};useEffect(() => {fetchActivities();if (userId) {fetchMyClubs();}}, [userId]);// 创建活动const handleCreateActivity = async (values) => {try {const { timeRange, ...rest } = values;await activityApi.createActivity({...rest,startTime: timeRange[0].format(),endTime: timeRange[1].format(),});message.success('创建活动成功');setCreateModalVisible(false);createForm.resetFields();fetchActivities();fetchMyClubs(); // 刷新社团活动} catch (error) {message.error('创建活动失败');}};// 活动报名const handleSignup = async () => {try {await activityApi.signup(selectedActivity.id, userId);message.success('报名成功');setSignupModalVisible(false);} catch (error) {message.error(error.response?.data?.message || '报名失败');}};// 活动签到const handleCheckin = async () => {try {await activityApi.checkin(selectedActivity.id, userId);message.success('签到成功');setCheckinModalVisible(false);} catch (error) {message.error(error.response?.data?.message || '签到失败');}};// 查看报名名单const viewSignups = async (activity) => {try {setSelectedActivity(activity);setLoading(true);const response = await activityApi.listSignups(activity.id);setSignups(response.data || []);setSignupsModalVisible(true);} catch (error) {message.error('获取报名名单失败');} finally {setLoading(false);}};// 获取社团名称const getClubName = (clubId) => {const club = clubs.find(c => c.id === clubId);return club ? club.name : `社团 ${clubId}`;};return (<div><Tabs defaultActiveKey="all"><TabPane tab={<span><CalendarOutlined />所有活动</span>} key="all"><Card title="活动列表" extra={<Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateModalVisible(true)}>创建活动</Button>}><Listloading={loading}grid={{ gutter: 16, column: 3 }}dataSource={activities}renderItem={activity => (<List.Item><Cardhoverableactions={[<Button onClick={() => {setSelectedActivity(activity);setSignupModalVisible(true);}}>报名</Button>,<Button onClick={() => {setSelectedActivity(activity);setCheckinModalVisible(true);}}>签到</Button>,<Button onClick={() => viewSignups(activity)}>名单</Button>]}><Card.Metaavatar={<Avatar icon={<ScheduleOutlined />} />}title={activity.title}description={<div><Paragraph ellipsis={{ rows: 2 }}>{activity.description || '暂无描述'}</Paragraph><div>社团: {getClubName(activity.clubId)}</div><div>开始: {new Date(activity.startTime).toLocaleString()}</div><div>结束: {new Date(activity.endTime).toLocaleString()}</div></div>}/></Card></List.Item>)}/></Card></TabPane><TabPane tab={<span><TeamOutlined />社团活动</span>} key="club"><Card title="我的社团活动"><Listloading={loading}grid={{ gutter: 16, column: 3 }}dataSource={clubActivities}renderItem={activity => (<List.Item><Cardhoverableactions={[<Button onClick={() => {setSelectedActivity(activity);setSignupModalVisible(true);}}>报名</Button>,<Button onClick={() => {setSelectedActivity(activity);setCheckinModalVisible(true);}}>签到</Button>,<Button onClick={() => viewSignups(activity)}>名单</Button>]}><Card.Metaavatar={<Avatar icon={<ScheduleOutlined />} />}title={activity.title}description={<div><Paragraph ellipsis={{ rows: 2 }}>{activity.description || '暂无描述'}</Paragraph><div>社团: {getClubName(activity.clubId)}</div><div>开始: {new Date(activity.startTime).toLocaleString()}</div><div>结束: {new Date(activity.endTime).toLocaleString()}</div></div>}/></Card></List.Item>)}/></Card></TabPane></Tabs>{/* 创建活动对话框 */}<Modaltitle="创建新活动"open={createModalVisible}onCancel={() => setCreateModalVisible(false)}footer={null}><Form form={createForm} onFinish={handleCreateActivity} layout="vertical"><Form.Itemname="title"label="活动名称"rules={[{ required: true, message: '请输入活动名称' }]}><Input placeholder="请输入活动名称" /></Form.Item><Form.Itemname="description"label="活动描述"><TextArea rows={4} placeholder="请输入活动描述" /></Form.Item><Form.Itemname="clubId"label="所属社团"rules={[{ required: true, message: '请选择所属社团' }]}><Select placeholder="请选择所属社团">{myClubs.map(item => {const club = clubs.find(c => c.id === item.clubId) || {};return (<Select.Option key={item.clubId} value={item.clubId}>{club.name || `社团 ${item.clubId}`}</Select.Option>);})}</Select></Form.Item><Form.Itemname="timeRange"label="活动时间"rules={[{ required: true, message: '请选择活动时间范围' }]}><RangePicker showTime format="YYYY-MM-DD HH:mm:ss" /></Form.Item><Form.Item><Button type="primary" htmlType="submit" block>创建</Button></Form.Item></Form></Modal>{/* 活动报名对话框 */}<Modaltitle={`报名活动: ${selectedActivity?.title}`}open={signupModalVisible}onCancel={() => setSignupModalVisible(false)}footer={null}><Paragraph>确定要报名参加该活动吗?</Paragraph><Button type="primary" onClick={handleSignup} block>确认报名</Button></Modal>{/* 活动签到对话框 */}<Modaltitle={`活动签到: ${selectedActivity?.title}`}open={checkinModalVisible}onCancel={() => setCheckinModalVisible(false)}footer={null}><Paragraph>确定要签到该活动吗?</Paragraph><Button type="primary" onClick={handleCheckin} block>确认签到</Button></Modal>{/* 查看报名名单对话框 */}<Modaltitle={`${selectedActivity?.title} 的报名名单`}open={signupsModalVisible}onCancel={() => setSignupsModalVisible(false)}footer={null}width={600}><Listloading={loading}dataSource={signups}renderItem={signup => (<List.Item><List.Item.Metaavatar={<Avatar icon={<UserOutlined />} />}title={signup.username || `用户 ${signup.userId}`}description={<div><div>报名时间: {new Date(signup.signupTime).toLocaleString()}</div><div>签到状态: {signup.checkedIn ? (<Tag color="green">已签到 ({new Date(signup.checkinTime).toLocaleString()})</Tag>) : (<Tag color="red">未签到</Tag>)}</div></div>}/></List.Item>)}/></Modal></div>);
}

frontend\src\modules\ClubModule.js

import React, { useState, useEffect } from 'react';
import { Card, List, Avatar, Button, Input, Form, Modal, message, Tabs, Typography, Divider, Tag } from 'antd';
import { UserOutlined, TeamOutlined, PlusOutlined, HomeOutlined } from '@ant-design/icons';
import { clubApi } from '../api';const { TabPane } = Tabs;
const { Title, Text, Paragraph } = Typography;
const { TextArea } = Input;export default function ClubModule() {const [clubs, setClubs] = useState([]);const [myClubs, setMyClubs] = useState([]);const [loading, setLoading] = useState(true);const [createModalVisible, setCreateModalVisible] = useState(false);const [joinModalVisible, setJoinModalVisible] = useState(false);const [selectedClub, setSelectedClub] = useState(null);const [members, setMembers] = useState([]);const [membersModalVisible, setMembersModalVisible] = useState(false);const [createForm] = Form.useForm();const [joinForm] = Form.useForm();const userId = localStorage.getItem('userId');// 获取社团列表const fetchClubs = async () => {try {setLoading(true);const response = await clubApi.listClubs();setClubs(response.data || []);} catch (error) {message.error('获取社团列表失败');} finally {setLoading(false);}};// 获取我的社团const fetchMyClubs = async () => {try {const response = await clubApi.listClubsByUser(userId);setMyClubs(response.data || []);} catch (error) {message.error('获取我的社团失败');}};useEffect(() => {fetchClubs();if (userId) {fetchMyClubs();}}, [userId]);// 创建社团const handleCreateClub = async (values) => {try {await clubApi.createClub({...values,creatorId: userId});message.success('创建社团成功');setCreateModalVisible(false);createForm.resetFields();fetchClubs();fetchMyClubs();} catch (error) {message.error(error.response?.data?.message || '创建社团失败');}};// 加入社团const handleJoinClub = async (values) => {try {await clubApi.joinClub({clubId: selectedClub.id,userId: userId});message.success('加入社团成功');setJoinModalVisible(false);joinForm.resetFields();fetchMyClubs();} catch (error) {message.error(error.response?.data?.message || '加入社团失败');}};// 查看社团成员const viewMembers = async (club) => {try {setSelectedClub(club);setLoading(true);const response = await clubApi.listMembers(club.id);setMembers(response.data || []);setMembersModalVisible(true);} catch (error) {message.error('获取社团成员失败');} finally {setLoading(false);}};return (<div><Tabs defaultActiveKey="all"><TabPane tab={<span><HomeOutlined />所有社团</span>} key="all"><Card title="社团列表" extra={<Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateModalVisible(true)}>创建社团</Button>}><Listloading={loading}grid={{ gutter: 16, column: 3 }}dataSource={clubs}renderItem={club => (<List.Item><Cardhoverableactions={[<Button onClick={() => {setSelectedClub(club);setJoinModalVisible(true);}}>加入</Button>,<Button onClick={() => viewMembers(club)}>成员</Button>]}><Card.Metaavatar={<Avatar icon={<TeamOutlined />} />}title={club.name}description={<div><Paragraph ellipsis={{ rows: 2 }}>{club.description || '暂无描述'}</Paragraph><div>创建于: {new Date(club.createdAt).toLocaleDateString()}</div></div>}/></Card></List.Item>)}/></Card></TabPane><TabPane tab={<span><TeamOutlined />我的社团</span>} key="my"><Card title="我加入的社团"><Listloading={loading}grid={{ gutter: 16, column: 3 }}dataSource={myClubs}renderItem={item => {const club = clubs.find(c => c.id === item.clubId) || {};return (<List.Item><Cardhoverableactions={[<Button onClick={() => viewMembers({ id: item.clubId, name: club.name })}>成员</Button>]}><Card.Metaavatar={<Avatar icon={<TeamOutlined />} />}title={<div>{club.name || `社团 ${item.clubId}`}<Tag color={item.role === 'president' ? 'gold' : 'blue'} style={{ marginLeft: 8 }}>{item.role === 'president' ? '会长' : '成员'}</Tag></div>}description={club.description || '暂无描述'}/></Card></List.Item>);}}/></Card></TabPane></Tabs>{/* 创建社团对话框 */}<Modaltitle="创建新社团"open={createModalVisible}onCancel={() => setCreateModalVisible(false)}footer={null}><Form form={createForm} onFinish={handleCreateClub} layout="vertical"><Form.Itemname="name"label="社团名称"rules={[{ required: true, message: '请输入社团名称' }]}><Input placeholder="请输入社团名称" /></Form.Item><Form.Itemname="description"label="社团描述"><TextArea rows={4} placeholder="请输入社团描述" /></Form.Item><Form.Item><Button type="primary" htmlType="submit" block>创建</Button></Form.Item></Form></Modal>{/* 加入社团对话框 */}<Modaltitle={`加入社团: ${selectedClub?.name}`}open={joinModalVisible}onCancel={() => setJoinModalVisible(false)}footer={null}><Form form={joinForm} onFinish={handleJoinClub} layout="vertical"><Paragraph>确定要加入该社团吗?</Paragraph><Form.Item><Button type="primary" htmlType="submit" block>确认加入</Button></Form.Item></Form></Modal>{/* 查看成员对话框 */}<Modaltitle={`${selectedClub?.name} 的成员`}open={membersModalVisible}onCancel={() => setMembersModalVisible(false)}footer={null}width={600}><Listloading={loading}dataSource={members}renderItem={member => (<List.Item><List.Item.Metaavatar={<Avatar icon={<UserOutlined />} />}title={<div>{member.username || `用户 ${member.userId}`}<Tag color={member.role === 'president' ? 'gold' : 'blue'} style={{ marginLeft: 8 }}>{member.role === 'president' ? '会长' : '成员'}</Tag></div>}/></List.Item>)}/></Modal></div>);
}

frontend\src\modules\FriendModule.js

import React, { useState, useEffect } from 'react';
import { Card, List, Avatar, Button, Input, Modal, Form, Select, Tabs, message, Typography, Divider } from 'antd';
import { UserOutlined, UserAddOutlined, TeamOutlined } from '@ant-design/icons';
import { friendApi } from '../api';const { TabPane } = Tabs;
const { Title, Text } = Typography;export default function FriendModule() {const [friends, setFriends] = useState([]);const [loading, setLoading] = useState(true);const [addModalVisible, setAddModalVisible] = useState(false);const [moveModalVisible, setMoveModalVisible] = useState(false);const [selectedFriend, setSelectedFriend] = useState(null);const [groups, setGroups] = useState(['default', '学习', '生活', '兴趣']);const [addForm] = Form.useForm();const [moveForm] = Form.useForm();const userId = localStorage.getItem('userId');// 获取好友列表const fetchFriends = async () => {try {setLoading(true);const response = await friendApi.listFriends(userId);setFriends(response.data || []);} catch (error) {message.error('获取好友列表失败');} finally {setLoading(false);}};useEffect(() => {if (userId) {fetchFriends();}}, [userId]);// 添加好友const handleAddFriend = async (values) => {try {await friendApi.addFriend({userId: userId,friendId: values.friendId,groupName: values.groupName || 'default'});message.success('添加好友成功');fetchFriends();setAddModalVisible(false);addForm.resetFields();} catch (error) {message.error(error.response?.data?.message || '添加好友失败');}};// 移动好友到其他分组const handleMoveFriend = async (values) => {try {await friendApi.moveFriend({id: selectedFriend.id,groupName: values.groupName});message.success('移动好友成功');fetchFriends();setMoveModalVisible(false);moveForm.resetFields();} catch (error) {message.error('移动好友失败');}};// 按分组组织好友const groupedFriends = friends.reduce((acc, friend) => {const group = friend.groupName || 'default';if (!acc[group]) acc[group] = [];acc[group].push(friend);return acc;}, {});return (<div><Cardtitle="好友管理"extra={<Button type="primary" icon={<UserAddOutlined />} onClick={() => setAddModalVisible(true)}>添加好友</Button>}><Tabs defaultActiveKey="all"><TabPane tab="全部好友" key="all"><Listloading={loading}dataSource={friends}renderItem={item => (<List.Itemactions={[<Button onClick={() => {setSelectedFriend(item);setMoveModalVisible(true);}}>移动到分组</Button>]}><List.Item.Metaavatar={<Avatar icon={<UserOutlined />} />}title={item.friendUsername}description={`分组: ${item.groupName || '默认'}`}/></List.Item>)}/></TabPane>{Object.keys(groupedFriends).map(group => (<TabPane tab={group === 'default' ? '默认分组' : group} key={group}><Listloading={loading}dataSource={groupedFriends[group]}renderItem={item => (<List.Itemactions={[<Button onClick={() => {setSelectedFriend(item);setMoveModalVisible(true);}}>移动到分组</Button>]}><List.Item.Metaavatar={<Avatar icon={<UserOutlined />} />}title={item.friendUsername}/></List.Item>)}/></TabPane>))}</Tabs></Card>{/* 添加好友对话框 */}<Modaltitle="添加好友"open={addModalVisible}onCancel={() => setAddModalVisible(false)}footer={null}><Form form={addForm} onFinish={handleAddFriend} layout="vertical"><Form.Itemname="friendId"label="好友 ID"rules={[{ required: true, message: '请输入好友 ID' }]}><Input placeholder="请输入好友的用户 ID" /></Form.Item><Form.Item name="groupName" label="分组"><Select placeholder="请选择分组">{groups.map(group => (<Select.Option key={group} value={group}>{group === 'default' ? '默认分组' : group}</Select.Option>))}</Select></Form.Item><Form.Item><Button type="primary" htmlType="submit" block>添加</Button></Form.Item></Form></Modal>{/* 移动好友对话框 */}<Modaltitle="移动好友到分组"open={moveModalVisible}onCancel={() => setMoveModalVisible(false)}footer={null}><Form form={moveForm} onFinish={handleMoveFriend} layout="vertical"><Form.Item name="groupName" label="选择分组" rules={[{ required: true, message: '请选择分组' }]}><Select placeholder="请选择分组">{groups.map(group => (<Select.Option key={group} value={group}>{group === 'default' ? '默认分组' : group}</Select.Option>))}</Select></Form.Item><Form.Item><Button type="primary" htmlType="submit" block>移动</Button></Form.Item></Form></Modal></div>);
}

frontend\src\modules\MessageModule.js

import React, { useState, useEffect } from 'react';
import { Card, List, Avatar, Button, Input, Form, message, Tabs, Badge, Typography, Divider } from 'antd';
import { UserOutlined, MessageOutlined, SendOutlined, BellOutlined } from '@ant-design/icons';
import { messageApi } from '../api';const { TabPane } = Tabs;
const { TextArea } = Input;
const { Title, Text } = Typography;export default function MessageModule() {const [messages, setMessages] = useState([]);const [loading, setLoading] = useState(true);const [selectedUser, setSelectedUser] = useState(null);const [conversationVisible, setConversationVisible] = useState(false);const [conversation, setConversation] = useState([]);const [form] = Form.useForm();const userId = localStorage.getItem('userId');// 获取消息列表const fetchMessages = async () => {try {setLoading(true);const response = await messageApi.listReceivedMessages(userId);setMessages(response.data || []);} catch (error) {message.error('获取消息列表失败');} finally {setLoading(false);}};useEffect(() => {if (userId) {fetchMessages();}}, [userId]);// 获取与特定用户的会话const fetchConversation = async (otherUserId) => {try {setLoading(true);const response = await messageApi.listConversation(userId, otherUserId);setConversation(response.data || []);} catch (error) {message.error('获取会话失败');} finally {setLoading(false);}};// 标记消息为已读const markAsRead = async (messageId) => {try {await messageApi.markAsRead(messageId);fetchMessages(); // 刷新消息列表} catch (error) {message.error('标记已读失败');}};// 发送消息const handleSendMessage = async (values) => {try {await messageApi.sendMessage(userId, {receiverId: selectedUser.senderId, // 对方IDcontent: values.content});message.success('发送消息成功');form.resetFields();// 刷新会话fetchConversation(selectedUser.senderId);} catch (error) {message.error('发送消息失败');}};// 查看会话const viewConversation = (msg) => {setSelectedUser(msg);fetchConversation(msg.senderId);setConversationVisible(true);// 如果是未读消息,标记为已读if (!msg.isRead) {markAsRead(msg.id);}};// 计算未读消息数const unreadCount = messages.filter(msg => !msg.isRead).length;return (<div><Tabs defaultActiveKey="inbox"><TabPane tab={<span><BellOutlined />消息通知 {unreadCount > 0 && <Badge count={unreadCount} />}</span>} key="inbox"><Card title="消息列表"><Listloading={loading}itemLayout="horizontal"dataSource={messages}renderItem={msg => (<List.Itemactions={[<Button type="primary" onClick={() => viewConversation(msg)}>查看</Button>]}><List.Item.Metaavatar={<Avatar icon={<UserOutlined />} />}title={<div><span>{msg.senderUsername || `用户 ${msg.senderId}`}</span>{!msg.isRead && <Badge color="blue" style={{ marginLeft: 8 }} />}</div>}description={<div style={{ width: '300px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{msg.content}</div>}/><div>{new Date(msg.createdAt).toLocaleString()}</div></List.Item>)}/></Card></TabPane></Tabs>{/* 会话对话框 */}{conversationVisible && selectedUser && (<Card title={`与 ${selectedUser.senderUsername || `用户 ${selectedUser.senderId}`} 的对话`}style={{ marginTop: 20 }}extra={<Button onClick={() => setConversationVisible(false)}>关闭</Button>}><div style={{ height: '300px', overflowY: 'auto', marginBottom: 16, padding: 16, background: '#f5f5f5', borderRadius: 4 }}>{conversation.map((msg, index) => (<div key={index} style={{display: 'flex', justifyContent: msg.senderId.toString() === userId.toString() ? 'flex-end' : 'flex-start',marginBottom: 16}}><div style={{background: msg.senderId.toString() === userId.toString() ? '#1890ff' : '#fff',color: msg.senderId.toString() === userId.toString() ? '#fff' : '#000',padding: '8px 12px',borderRadius: 8,maxWidth: '70%',boxShadow: '0 1px 2px rgba(0,0,0,0.1)'}}><div>{msg.content}</div><div style={{ fontSize: '12px', marginTop: 4, opacity: 0.7 }}>{new Date(msg.createdAt).toLocaleString()}</div></div></div>))}</div><Form form={form} onFinish={handleSendMessage}><Form.Itemname="content"rules={[{ required: true, message: '请输入消息内容' }]}><TextArea rows={3} placeholder="输入消息..." /></Form.Item><Form.Item><Button type="primary" htmlType="submit" icon={<SendOutlined />}>发送</Button></Form.Item></Form></Card>)}</div>);
}

frontend\src\modules\PostModule.js

import React, { useState, useEffect } from 'react';
import { Card, List, Avatar, Button, Input, Form, message, Divider, Upload, Modal, Image, Typography, Comment } from 'antd';
import { UserOutlined, PictureOutlined, SendOutlined, CommentOutlined, LikeOutlined } from '@ant-design/icons';
import { postApi } from '../api';const { TextArea } = Input;
const { Title, Text, Paragraph } = Typography;export default function PostModule() {const [posts, setPosts] = useState([]);const [loading, setLoading] = useState(true);const [commentForm] = Form.useForm();const [selectedPost, setSelectedPost] = useState(null);const [commentModalVisible, setCommentModalVisible] = useState(false);const userId = localStorage.getItem('userId');// 获取动态列表const fetchPosts = async () => {try {setLoading(true);const response = await postApi.listPosts(userId);setPosts(response.data || []);} catch (error) {message.error('获取动态列表失败');} finally {setLoading(false);}};useEffect(() => {if (userId) {fetchPosts();}}, [userId]);// 发布新动态const handleCreatePost = async (values) => {try {await postApi.createPost({userId: userId,content: values.content,imageUrl: values.imageUrl || ''});message.success('发布动态成功');fetchPosts();form.resetFields();} catch (error) {message.error('发布动态失败');}};// 发表评论const handleComment = async (values) => {try {await postApi.createComment({postId: selectedPost.id,userId: userId,content: values.content});message.success('评论成功');setCommentModalVisible(false);commentForm.resetFields();fetchPosts(); // 刷新帖子列表} catch (error) {message.error('评论失败');}};// 创建新动态表单const [form] = Form.useForm();return (<div>{/* 发布新动态 */}<Card title="发布新动态"><Form form={form} onFinish={handleCreatePost} layout="vertical"><Form.Itemname="content"rules={[{ required: true, message: '请输入动态内容' }]}><TextArea rows={4} placeholder="分享你的想法..." /></Form.Item><Form.Item name="imageUrl"><Input placeholder="图片URL(可选)" prefix={<PictureOutlined />} /></Form.Item><Form.Item><Button type="primary" htmlType="submit" icon={<SendOutlined />}>发布</Button></Form.Item></Form></Card><Divider />{/* 动态列表 */}<Card title="动态列表"><Listloading={loading}itemLayout="vertical"dataSource={posts}renderItem={post => (<List.Itemkey={post.id}actions={[<Button icon={<CommentOutlined />} onClick={() => {setSelectedPost(post);setCommentModalVisible(true);}}>评论</Button>,<Button icon={<LikeOutlined />}>点赞</Button>]}><List.Item.Metaavatar={<Avatar icon={<UserOutlined />} />}title={post.username || `用户 ${post.userId}`}description={new Date(post.createdAt).toLocaleString()}/><Paragraph>{post.content}</Paragraph>{post.imageUrl && (<div style={{ marginTop: 16 }}><Image width={200} src={post.imageUrl} alt="动态图片"fallback="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l739v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="/></div>)}{/* 显示评论 */}{post.comments && post.comments.length > 0 && (<div style={{ marginTop: 16, background: '#f9f9f9', padding: 16, borderRadius: 4 }}><Text strong>评论:</Text><ListitemLayout="horizontal"dataSource={post.comments}renderItem={comment => (<Commentauthor={comment.username || `用户 ${comment.userId}`}avatar={<Avatar icon={<UserOutlined />} />}content={comment.content}datetime={new Date(comment.createdAt).toLocaleString()}/>)}/></div>)}</List.Item>)}/></Card>{/* 评论对话框 */}<Modaltitle="发表评论"open={commentModalVisible}onCancel={() => setCommentModalVisible(false)}footer={null}><Form form={commentForm} onFinish={handleComment} layout="vertical"><Form.Itemname="content"rules={[{ required: true, message: '请输入评论内容' }]}><TextArea rows={4} placeholder="输入你的评论..." /></Form.Item><Form.Item><Button type="primary" htmlType="submit" block>提交评论</Button></Form.Item></Form></Modal></div>);
}

frontend\src\modules\UserModule.js

import React, { useState, useEffect } from 'react';
import { Routes, Route, useNavigate } from 'react-router-dom';
import { Form, Input, Button, Card, message, Tabs, Avatar, Typography } from 'antd';
import { UserOutlined, LockOutlined, MailOutlined, IdcardOutlined } from '@ant-design/icons';
import { userApi } from '../api';const { Title, Text } = Typography;// 登录页面
function Login() {const navigate = useNavigate();const [loading, setLoading] = useState(false);const onFinish = async (values) => {try {setLoading(true);const response = await userApi.login(values);localStorage.setItem('token', response.data.token);localStorage.setItem('userId', response.data.id);message.success('登录成功');navigate('/user/profile');} catch (error) {message.error(error.response?.data?.message || '登录失败');} finally {setLoading(false);}};return (<Card title="用户登录" style={{ maxWidth: 400, margin: '0 auto' }}><Form name="login" onFinish={onFinish}><Form.Itemname="username"rules={[{ required: true, message: '请输入用户名' }]}><Input prefix={<UserOutlined />} placeholder="用户名" /></Form.Item><Form.Itemname="password"rules={[{ required: true, message: '请输入密码' }]}><Input.Password prefix={<LockOutlined />} placeholder="密码" /></Form.Item><Form.Item><Button type="primary" htmlType="submit" block loading={loading}>登录</Button><div style={{ marginTop: 16, textAlign: 'center' }}><a onClick={() => navigate('/user/register')}>没有账号?立即注册</a></div></Form.Item></Form></Card>);
}// 注册页面
function Register() {const navigate = useNavigate();const [loading, setLoading] = useState(false);const onFinish = async (values) => {try {setLoading(true);await userApi.register(values);message.success('注册成功,请登录');navigate('/user/login');} catch (error) {message.error(error.response?.data?.message || '注册失败');} finally {setLoading(false);}};return (<Card title="用户注册" style={{ maxWidth: 400, margin: '0 auto' }}><Form name="register" onFinish={onFinish}><Form.Itemname="username"rules={[{ required: true, message: '请输入用户名' }]}><Input prefix={<UserOutlined />} placeholder="用户名" /></Form.Item><Form.Itemname="password"rules={[{ required: true, message: '请输入密码' }]}><Input.Password prefix={<LockOutlined />} placeholder="密码" /></Form.Item><Form.Itemname="email"rules={[{ required: true, message: '请输入邮箱' },{ type: 'email', message: '请输入有效的邮箱地址' }]}><Input prefix={<MailOutlined />} placeholder="邮箱" /></Form.Item><Form.Itemname="realName"rules={[{ required: true, message: '请输入真实姓名' }]}><Input prefix={<IdcardOutlined />} placeholder="真实姓名" /></Form.Item><Form.Itemname="role"initialValue="student"hidden><Input /></Form.Item><Form.Item><Button type="primary" htmlType="submit" block loading={loading}>注册</Button><div style={{ marginTop: 16, textAlign: 'center' }}><a onClick={() => navigate('/user/login')}>已有账号?立即登录</a></div></Form.Item></Form></Card>);
}// 个人资料页面
function Profile() {const [user, setUser] = useState(null);const [loading, setLoading] = useState(true);const userId = localStorage.getItem('userId');useEffect(() => {const fetchProfile = async () => {try {const response = await userApi.getProfile(userId);setUser(response.data);} catch (error) {message.error('获取个人资料失败');} finally {setLoading(false);}};if (userId) {fetchProfile();}}, [userId]);if (loading) return <div>加载中...</div>;if (!user) return <div>请先登录</div>;return (<Card title="个人资料" style={{ maxWidth: 600, margin: '0 auto' }}><div style={{ display: 'flex', alignItems: 'center', marginBottom: 20 }}><Avatar size={64} icon={<UserOutlined />} /><div style={{ marginLeft: 20 }}><Title level={4}>{user.username}</Title><Text type="secondary">{user.role === 'student' ? '学生' : '教师'}</Text></div></div><Form layout="vertical"><Form.Item label="真实姓名"><Input value={user.realName} readOnly /></Form.Item><Form.Item label="邮箱"><Input value={user.email} readOnly /></Form.Item></Form></Card>);
}// 用户模块主组件
export default function UserModule() {return (<Routes><Route path="/login" element={<Login />} /><Route path="/register" element={<Register />} /><Route path="/profile" element={<Profile />} /><Route path="*" element={<Login />} /></Routes>);
}

src\main\java\com\example\campus\CampusSocialNetworkApplication.java

package com.example.campus;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class CampusSocialNetworkApplication {public static void main(String[] args) {SpringApplication.run(CampusSocialNetworkApplication.class, args);}
}

src\main\java\com\example\campus\controller\ActivityController.java

package com.example.campus.controller;import com.example.campus.dto.CreateActivityRequest;
import com.example.campus.entity.Activity;
import com.example.campus.entity.ActivitySignup;
import com.example.campus.service.ActivityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;@RestController
@RequestMapping("/api/activity")
public class ActivityController {@Autowiredprivate ActivityService activityService;// 创建活动@PostMapping("/create")public Activity createActivity(@RequestBody CreateActivityRequest req) {return activityService.createActivity(req);}// 查询所有活动@GetMapping("/list")public List<Activity> listAllActivities() {return activityService.listAllActivities();}// 查询社团的活动@GetMapping("/club/{clubId}")public List<Activity> listActivitiesByClub(@PathVariable Long clubId) {return activityService.listActivitiesByClub(clubId);}// 活动报名@PostMapping("/{activityId}/signup/{userId}")public ActivitySignup signup(@PathVariable Long activityId, @PathVariable Long userId) {return activityService.signup(activityId, userId);}// 查看活动报名名单@GetMapping("/{activityId}/signups")public List<ActivitySignup> listSignups(@PathVariable Long activityId) {return activityService.listSignups(activityId);}// 活动签到@PutMapping("/{activityId}/checkin/{userId}")public ActivitySignup checkin(@PathVariable Long activityId, @PathVariable Long userId) {return activityService.checkin(activityId, userId);}
}

src\main\java\com\example\campus\controller\AuthController.java

package com.example.campus.controller;import com.example.campus.dto.RegisterRequest;
import com.example.campus.dto.LoginRequest;
import com.example.campus.entity.User;
import com.example.campus.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api/auth")
public class AuthController {@Autowiredprivate UserService userService;@PostMapping("/register")public User register(@RequestBody RegisterRequest request) {return userService.register(request);}@PostMapping("/login")public User login(@RequestBody LoginRequest request) {return userService.login(request);}
}

src\main\java\com\example\campus\controller\ClubController.java

package com.example.campus.controller;import com.example.campus.dto.CreateClubRequest;
import com.example.campus.dto.JoinClubRequest;
import com.example.campus.entity.Club;
import com.example.campus.entity.ClubMember;
import com.example.campus.service.ClubService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;@RestController
@RequestMapping("/api/club")
public class ClubController {@Autowiredprivate ClubService clubService;// 创建社团@PostMapping("/create")public Club createClub(@RequestBody CreateClubRequest req) {return clubService.createClub(req);}// 查询所有社团@GetMapping("/list")public List<Club> listClubs() {return clubService.listClubs();}// 查询社团成员@GetMapping("/{clubId}/members")public List<ClubMember> listMembers(@PathVariable Long clubId) {return clubService.listMembers(clubId);}// 加入社团@PostMapping("/join")public ClubMember joinClub(@RequestBody JoinClubRequest req) {return clubService.joinClub(req);}// 查询用户加入的所有社团@GetMapping("/user/{userId}")public List<ClubMember> listClubsByUser(@PathVariable Long userId) {return clubService.listClubsByUser(userId);}
}

src\main\java\com\example\campus\controller\FriendController.java

package com.example.campus.controller;import com.example.campus.dto.AddFriendRequest;
import com.example.campus.dto.MoveFriendRequest;
import com.example.campus.entity.Friend;
import com.example.campus.service.FriendService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/api/friend")
public class FriendController {@Autowiredprivate FriendService friendService;// 添加好友@PostMapping("/{userId}/add")public Friend addFriend(@PathVariable Long userId, @RequestBody AddFriendRequest req) {return friendService.addFriend(userId, req);}// 查询好友列表@GetMapping("/{userId}/list")public List<Friend> listFriends(@PathVariable Long userId) {return friendService.listFriends(userId);}// 按分组查询@GetMapping("/{userId}/group/{groupName}")public List<Friend> listFriendsByGroup(@PathVariable Long userId, @PathVariable String groupName) {return friendService.listFriendsByGroup(userId, groupName);}// 移动分组@PutMapping("/{userId}/move")public Friend moveFriend(@PathVariable Long userId, @RequestBody MoveFriendRequest req) {return friendService.moveFriend(userId, req);}
}

src\main\java\com\example\campus\controller\MessageController.java

package com.example.campus.controller;import com.example.campus.dto.SendMessageRequest;
import com.example.campus.entity.Message;
import com.example.campus.service.MessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;@RestController
@RequestMapping("/api/message")
public class MessageController {@Autowiredprivate MessageService messageService;// 发送私信@PostMapping("/{senderId}/send")public Message sendMessage(@PathVariable Long senderId, @RequestBody SendMessageRequest req) {return messageService.sendMessage(senderId, req);}// 查询收到的消息@GetMapping("/received/{receiverId}")public List<Message> listReceivedMessages(@PathVariable Long receiverId) {return messageService.listReceivedMessages(receiverId);}// 查询与某用户的会话@GetMapping("/conversation/{userId1}/{userId2}")public List<Message> listConversation(@PathVariable Long userId1, @PathVariable Long userId2) {return messageService.listConversation(userId1, userId2);}// 标记消息为已读@PutMapping("/read/{messageId}")public Message markAsRead(@PathVariable Long messageId) {return messageService.markAsRead(messageId);}
}

src\main\java\com\example\campus\controller\PostController.java

package com.example.campus.controller;import com.example.campus.dto.CreatePostRequest;
import com.example.campus.dto.CreateCommentRequest;
import com.example.campus.entity.Post;
import com.example.campus.entity.Comment;
import com.example.campus.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;@RestController
@RequestMapping("/api/post")
public class PostController {@Autowiredprivate PostService postService;// 发布动态@PostMapping("/create")public Post createPost(@RequestBody CreatePostRequest req) {return postService.createPost(req);}// 查询所有动态@GetMapping("/list")public List<Post> listAllPosts() {return postService.listAllPosts();}// 查询某用户动态@GetMapping("/user/{userId}")public List<Post> listPostsByUser(@PathVariable Long userId) {return postService.listPostsByUser(userId);}// 发布评论@PostMapping("/comment")public Comment createComment(@RequestBody CreateCommentRequest req) {return postService.createComment(req);}// 查询某动态下所有评论@GetMapping("/{postId}/comments")public List<Comment> listCommentsByPost(@PathVariable Long postId) {return postService.listCommentsByPost(postId);}
}

src\main\java\com\example\campus\controller\UserController.java

package com.example.campus.controller;import com.example.campus.entity.User;
import com.example.campus.service.UserService;
import com.example.campus.dto.UpdateProfileRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api/user")
public class UserController {@Autowiredprivate UserService userService;// 获取个人信息@GetMapping("/{id}")public User getProfile(@PathVariable Long id) {return userService.getUserById(id);}// 更新个人信息@PutMapping("/{id}")public User updateProfile(@PathVariable Long id, @RequestBody UpdateProfileRequest request) {return userService.updateProfile(id, request);}
}

src\main\java\com\example\campus\dto\AddFriendRequest.java

package com.example.campus.dto;public class AddFriendRequest {private Long friendId;private String groupName;public Long getFriendId() { return friendId; }public void setFriendId(Long friendId) { this.friendId = friendId; }public String getGroupName() { return groupName; }public void setGroupName(String groupName) { this.groupName = groupName; }
}

src\main\java\com\example\campus\dto\CreateActivityRequest.java

package com.example.campus.dto;import java.sql.Timestamp;public class CreateActivityRequest {private String title;private String description;private Long clubId;private Timestamp startTime;private Timestamp endTime;public String getTitle() { return title; }public void setTitle(String title) { this.title = title; }public String getDescription() { return description; }public void setDescription(String description) { this.description = description; }public Long getClubId() { return clubId; }public void setClubId(Long clubId) { this.clubId = clubId; }public Timestamp getStartTime() { return startTime; }public void setStartTime(Timestamp startTime) { this.startTime = startTime; }public Timestamp getEndTime() { return endTime; }public void setEndTime(Timestamp endTime) { this.endTime = endTime; }
}

src\main\java\com\example\campus\dto\CreateClubRequest.java

package com.example.campus.dto;public class CreateClubRequest {private String name;private String description;private Long creatorId;public String getName() { return name; }public void setName(String name) { this.name = name; }public String getDescription() { return description; }public void setDescription(String description) { this.description = description; }public Long getCreatorId() { return creatorId; }public void setCreatorId(Long creatorId) { this.creatorId = creatorId; }
}

src\main\java\com\example\campus\dto\CreateCommentRequest.java

package com.example.campus.dto;public class CreateCommentRequest {private Long postId;private Long userId;private String content;public Long getPostId() { return postId; }public void setPostId(Long postId) { this.postId = postId; }public Long getUserId() { return userId; }public void setUserId(Long userId) { this.userId = userId; }public String getContent() { return content; }public void setContent(String content) { this.content = content; }
}

src\main\java\com\example\campus\dto\CreatePostRequest.java

package com.example.campus.dto;public class CreatePostRequest {private Long userId;private String content;private String imageUrl;public Long getUserId() { return userId; }public void setUserId(Long userId) { this.userId = userId; }public String getContent() { return content; }public void setContent(String content) { this.content = content; }public String getImageUrl() { return imageUrl; }public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
}

src\main\java\com\example\campus\dto\JoinClubRequest.java

package com.example.campus.dto;public class JoinClubRequest {private Long clubId;private Long userId;public Long getClubId() { return clubId; }public void setClubId(Long clubId) { this.clubId = clubId; }public Long getUserId() { return userId; }public void setUserId(Long userId) { this.userId = userId; }
}

src\main\java\com\example\campus\dto\LoginRequest.java

package com.example.campus.dto;public class LoginRequest {private String username;private String password;// getters and setterspublic String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getPassword() { return password; }public void setPassword(String password) { this.password = password; }
}

src\main\java\com\example\campus\dto\MoveFriendRequest.java

package com.example.campus.dto;public class MoveFriendRequest {private Long friendId;private String newGroupName;public Long getFriendId() { return friendId; }public void setFriendId(Long friendId) { this.friendId = friendId; }public String getNewGroupName() { return newGroupName; }public void setNewGroupName(String newGroupName) { this.newGroupName = newGroupName; }
}

src\main\java\com\example\campus\dto\RegisterRequest.java

package com.example.campus.dto;public class RegisterRequest {private String username;private String password;private String role; // student or teacherprivate String email;private String realName;// getters and setterspublic String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getPassword() { return password; }public void setPassword(String password) { this.password = password; }public String getRole() { return role; }public void setRole(String role) { this.role = role; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public String getRealName() { return realName; }public void setRealName(String realName) { this.realName = realName; }
}

src\main\java\com\example\campus\dto\SendMessageRequest.java

package com.example.campus.dto;public class SendMessageRequest {private Long receiverId;private String content;public Long getReceiverId() { return receiverId; }public void setReceiverId(Long receiverId) { this.receiverId = receiverId; }public String getContent() { return content; }public void setContent(String content) { this.content = content; }
}

src\main\java\com\example\campus\dto\UpdateProfileRequest.java

package com.example.campus.dto;public class UpdateProfileRequest {private String email;private String realName;// 可扩展更多字段public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public String getRealName() { return realName; }public void setRealName(String realName) { this.realName = realName; }
}

src\main\java\com\example\campus\entity\Activity.java

package com.example.campus.entity;import javax.persistence.*;
import java.sql.Timestamp;@Entity
@Table(name = "activity")
public class Activity {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false)private String title;private String description;private Long clubId;@Column(name = "start_time")private Timestamp startTime;@Column(name = "end_time")private Timestamp endTime;@Column(name = "created_at")private Timestamp createdAt;// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getTitle() { return title; }public void setTitle(String title) { this.title = title; }public String getDescription() { return description; }public void setDescription(String description) { this.description = description; }public Long getClubId() { return clubId; }public void setClubId(Long clubId) { this.clubId = clubId; }public Timestamp getStartTime() { return startTime; }public void setStartTime(Timestamp startTime) { this.startTime = startTime; }public Timestamp getEndTime() { return endTime; }public void setEndTime(Timestamp endTime) { this.endTime = endTime; }public Timestamp getCreatedAt() { return createdAt; }public void setCreatedAt(Timestamp createdAt) { this.createdAt = createdAt; }
}

src\main\java\com\example\campus\entity\ActivitySignup.java

package com.example.campus.entity;import javax.persistence.*;
import java.sql.Timestamp;@Entity
@Table(name = "activity_signup")
public class ActivitySignup {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false)private Long activityId;@Column(nullable = false)private Long userId;@Column(nullable = false)private Boolean checkedIn = false;@Column(name = "signup_time")private Timestamp signupTime;@Column(name = "checkin_time")private Timestamp checkinTime;// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public Long getActivityId() { return activityId; }public void setActivityId(Long activityId) { this.activityId = activityId; }public Long getUserId() { return userId; }public void setUserId(Long userId) { this.userId = userId; }public Boolean getCheckedIn() { return checkedIn; }public void setCheckedIn(Boolean checkedIn) { this.checkedIn = checkedIn; }public Timestamp getSignupTime() { return signupTime; }public void setSignupTime(Timestamp signupTime) { this.signupTime = signupTime; }public Timestamp getCheckinTime() { return checkinTime; }public void setCheckinTime(Timestamp checkinTime) { this.checkinTime = checkinTime; }
}

src\main\java\com\example\campus\entity\Club.java

package com.example.campus.entity;import javax.persistence.*;
import java.sql.Timestamp;@Entity
@Table(name = "club")
public class Club {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false, unique = true)private String name;private String description;private Long creatorId;@Column(name = "created_at")private Timestamp createdAt;// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getName() { return name; }public void setName(String name) { this.name = name; }public String getDescription() { return description; }public void setDescription(String description) { this.description = description; }public Long getCreatorId() { return creatorId; }public void setCreatorId(Long creatorId) { this.creatorId = creatorId; }public Timestamp getCreatedAt() { return createdAt; }public void setCreatedAt(Timestamp createdAt) { this.createdAt = createdAt; }
}

src\main\java\com\example\campus\entity\ClubMember.java

package com.example.campus.entity;import javax.persistence.*;@Entity
@Table(name = "club_member")
public class ClubMember {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false)private Long clubId;@Column(nullable = false)private Long userId;@Column(nullable = false)private String role; // president/member// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public Long getClubId() { return clubId; }public void setClubId(Long clubId) { this.clubId = clubId; }public Long getUserId() { return userId; }public void setUserId(Long userId) { this.userId = userId; }public String getRole() { return role; }public void setRole(String role) { this.role = role; }
}

src\main\java\com\example\campus\entity\Comment.java

package com.example.campus.entity;import javax.persistence.*;
import java.sql.Timestamp;@Entity
@Table(name = "comment")
public class Comment {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false)private Long postId;@Column(nullable = false)private Long userId;@Column(nullable = false, length = 500)private String content;@Column(name = "created_at")private Timestamp createdAt;// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public Long getPostId() { return postId; }public void setPostId(Long postId) { this.postId = postId; }public Long getUserId() { return userId; }public void setUserId(Long userId) { this.userId = userId; }public String getContent() { return content; }public void setContent(String content) { this.content = content; }public Timestamp getCreatedAt() { return createdAt; }public void setCreatedAt(Timestamp createdAt) { this.createdAt = createdAt; }
}

src\main\java\com\example\campus\entity\Friend.java

package com.example.campus.entity;import javax.persistence.*;@Entity
@Table(name = "friend")
public class Friend {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false)private Long userId; // 自己的ID@Column(nullable = false)private Long friendId; // 好友的ID@Column(nullable = false)private String groupName; // 分组名// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public Long getUserId() { return userId; }public void setUserId(Long userId) { this.userId = userId; }public Long getFriendId() { return friendId; }public void setFriendId(Long friendId) { this.friendId = friendId; }public String getGroupName() { return groupName; }public void setGroupName(String groupName) { this.groupName = groupName; }
}

src\main\java\com\example\campus\entity\Message.java

package com.example.campus.entity;import javax.persistence.*;
import java.sql.Timestamp;@Entity
@Table(name = "message")
public class Message {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false)private Long senderId;@Column(nullable = false)private Long receiverId;@Column(nullable = false, length = 1000)private String content;@Column(nullable = false)private Boolean isRead = false;@Column(name = "created_at")private Timestamp createdAt;// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public Long getSenderId() { return senderId; }public void setSenderId(Long senderId) { this.senderId = senderId; }public Long getReceiverId() { return receiverId; }public void setReceiverId(Long receiverId) { this.receiverId = receiverId; }public String getContent() { return content; }public void setContent(String content) { this.content = content; }public Boolean getIsRead() { return isRead; }public void setIsRead(Boolean isRead) { this.isRead = isRead; }public Timestamp getCreatedAt() { return createdAt; }public void setCreatedAt(Timestamp createdAt) { this.createdAt = createdAt; }
}

src\main\java\com\example\campus\entity\Post.java

package com.example.campus.entity;import javax.persistence.*;
import java.sql.Timestamp;@Entity
@Table(name = "post")
public class Post {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false)private Long userId;@Column(nullable = false, length = 1000)private String content;private String imageUrl;@Column(name = "created_at")private Timestamp createdAt;// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public Long getUserId() { return userId; }public void setUserId(Long userId) { this.userId = userId; }public String getContent() { return content; }public void setContent(String content) { this.content = content; }public String getImageUrl() { return imageUrl; }public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }public Timestamp getCreatedAt() { return createdAt; }public void setCreatedAt(Timestamp createdAt) { this.createdAt = createdAt; }
}

src\main\java\com\example\campus\entity\User.java

package com.example.campus.entity;import javax.persistence.*;
import java.sql.Timestamp;@Entity
@Table(name = "user")
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false, unique = true)private String username;@Column(nullable = false)private String password;@Column(nullable = false)private String role; // student or teacherprivate String email;@Column(name = "real_name")private String realName;@Column(name = "created_at")private Timestamp createdAt;// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getPassword() { return password; }public void setPassword(String password) { this.password = password; }public String getRole() { return role; }public void setRole(String role) { this.role = role; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public String getRealName() { return realName; }public void setRealName(String realName) { this.realName = realName; }public Timestamp getCreatedAt() { return createdAt; }public void setCreatedAt(Timestamp createdAt) { this.createdAt = createdAt; }
}

src\main\java\com\example\campus\repository\ActivityRepository.java

package com.example.campus.repository;import com.example.campus.entity.Activity;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;public interface ActivityRepository extends JpaRepository<Activity, Long> {List<Activity> findByClubId(Long clubId);
}

src\main\java\com\example\campus\repository\ActivitySignupRepository.java

package com.example.campus.repository;import com.example.campus.entity.ActivitySignup;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;public interface ActivitySignupRepository extends JpaRepository<ActivitySignup, Long> {List<ActivitySignup> findByActivityId(Long activityId);ActivitySignup findByActivityIdAndUserId(Long activityId, Long userId);
}

src\main\java\com\example\campus\repository\ClubMemberRepository.java

package com.example.campus.repository;import com.example.campus.entity.ClubMember;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;public interface ClubMemberRepository extends JpaRepository<ClubMember, Long> {List<ClubMember> findByClubId(Long clubId);List<ClubMember> findByUserId(Long userId);ClubMember findByClubIdAndUserId(Long clubId, Long userId);
}

src\main\java\com\example\campus\repository\ClubRepository.java

package com.example.campus.repository;import com.example.campus.entity.Club;
import org.springframework.data.jpa.repository.JpaRepository;public interface ClubRepository extends JpaRepository<Club, Long> {Club findByName(String name);
}

src\main\java\com\example\campus\repository\CommentRepository.java

package com.example.campus.repository;import com.example.campus.entity.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;public interface CommentRepository extends JpaRepository<Comment, Long> {List<Comment> findByPostId(Long postId);
}

src\main\java\com\example\campus\repository\FriendRepository.java

package com.example.campus.repository;import com.example.campus.entity.Friend;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;public interface FriendRepository extends JpaRepository<Friend, Long> {List<Friend> findByUserId(Long userId);List<Friend> findByUserIdAndGroupName(Long userId, String groupName);Friend findByUserIdAndFriendId(Long userId, Long friendId);
}

src\main\java\com\example\campus\repository\MessageRepository.java

package com.example.campus.repository;import com.example.campus.entity.Message;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;public interface MessageRepository extends JpaRepository<Message, Long> {List<Message> findByReceiverId(Long receiverId);List<Message> findBySenderIdAndReceiverId(Long senderId, Long receiverId);
}

src\main\java\com\example\campus\repository\PostRepository.java

package com.example.campus.repository;import com.example.campus.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;public interface PostRepository extends JpaRepository<Post, Long> {List<Post> findByUserId(Long userId);
}

src\main\java\com\example\campus\repository\UserRepository.java

package com.example.campus.repository;import com.example.campus.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;public interface UserRepository extends JpaRepository<User, Long> {Optional<User> findByUsername(String username);
}

src\main\java\com\example\campus\service\ActivityService.java

package com.example.campus.service;import com.example.campus.dto.CreateActivityRequest;
import com.example.campus.entity.Activity;
import com.example.campus.entity.ActivitySignup;
import com.example.campus.repository.ActivityRepository;
import com.example.campus.repository.ActivitySignupRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.List;@Service
public class ActivityService {@Autowiredprivate ActivityRepository activityRepository;@Autowiredprivate ActivitySignupRepository activitySignupRepository;public Activity createActivity(CreateActivityRequest req) {Activity activity = new Activity();activity.setTitle(req.getTitle());activity.setDescription(req.getDescription());activity.setClubId(req.getClubId());activity.setStartTime(req.getStartTime());activity.setEndTime(req.getEndTime());activity.setCreatedAt(new Timestamp(System.currentTimeMillis()));return activityRepository.save(activity);}public List<Activity> listActivitiesByClub(Long clubId) {return activityRepository.findByClubId(clubId);}public List<Activity> listAllActivities() {return activityRepository.findAll();}public ActivitySignup signup(Long activityId, Long userId) {if (activitySignupRepository.findByActivityIdAndUserId(activityId, userId) != null) {throw new RuntimeException("已报名");}ActivitySignup signup = new ActivitySignup();signup.setActivityId(activityId);signup.setUserId(userId);signup.setCheckedIn(false);signup.setSignupTime(new Timestamp(System.currentTimeMillis()));return activitySignupRepository.save(signup);}public List<ActivitySignup> listSignups(Long activityId) {return activitySignupRepository.findByActivityId(activityId);}public ActivitySignup checkin(Long activityId, Long userId) {ActivitySignup signup = activitySignupRepository.findByActivityIdAndUserId(activityId, userId);if (signup == null) throw new RuntimeException("未报名");signup.setCheckedIn(true);signup.setCheckinTime(new Timestamp(System.currentTimeMillis()));return activitySignupRepository.save(signup);}
}

src\main\java\com\example\campus\service\ClubService.java

package com.example.campus.service;import com.example.campus.dto.CreateClubRequest;
import com.example.campus.dto.JoinClubRequest;
import com.example.campus.entity.Club;
import com.example.campus.entity.ClubMember;
import com.example.campus.repository.ClubRepository;
import com.example.campus.repository.ClubMemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.List;@Service
public class ClubService {@Autowiredprivate ClubRepository clubRepository;@Autowiredprivate ClubMemberRepository clubMemberRepository;public Club createClub(CreateClubRequest req) {if (clubRepository.findByName(req.getName()) != null) {throw new RuntimeException("社团名已存在");}Club club = new Club();club.setName(req.getName());club.setDescription(req.getDescription());club.setCreatorId(req.getCreatorId());club.setCreatedAt(new Timestamp(System.currentTimeMillis()));club = clubRepository.save(club);// 创始人自动成为社团会长ClubMember member = new ClubMember();member.setClubId(club.getId());member.setUserId(req.getCreatorId());member.setRole("president");clubMemberRepository.save(member);return club;}public List<Club> listClubs() {return clubRepository.findAll();}public List<ClubMember> listMembers(Long clubId) {return clubMemberRepository.findByClubId(clubId);}public ClubMember joinClub(JoinClubRequest req) {if (clubMemberRepository.findByClubIdAndUserId(req.getClubId(), req.getUserId()) != null) {throw new RuntimeException("已加入该社团");}ClubMember member = new ClubMember();member.setClubId(req.getClubId());member.setUserId(req.getUserId());member.setRole("member");return clubMemberRepository.save(member);}public List<ClubMember> listClubsByUser(Long userId) {return clubMemberRepository.findByUserId(userId);}
}

src\main\java\com\example\campus\service\FriendService.java

package com.example.campus.service;import com.example.campus.dto.AddFriendRequest;
import com.example.campus.dto.MoveFriendRequest;
import com.example.campus.entity.Friend;
import com.example.campus.repository.FriendRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class FriendService {@Autowiredprivate FriendRepository friendRepository;public Friend addFriend(Long userId, AddFriendRequest req) {// 检查是否已是好友if (friendRepository.findByUserIdAndFriendId(userId, req.getFriendId()) != null) {throw new RuntimeException("已添加为好友");}Friend friend = new Friend();friend.setUserId(userId);friend.setFriendId(req.getFriendId());friend.setGroupName(req.getGroupName() != null ? req.getGroupName() : "默认分组");return friendRepository.save(friend);}public List<Friend> listFriends(Long userId) {return friendRepository.findByUserId(userId);}public List<Friend> listFriendsByGroup(Long userId, String groupName) {return friendRepository.findByUserIdAndGroupName(userId, groupName);}public Friend moveFriend(Long userId, MoveFriendRequest req) {Friend friend = friendRepository.findByUserIdAndFriendId(userId, req.getFriendId());if (friend == null) throw new RuntimeException("好友不存在");friend.setGroupName(req.getNewGroupName());return friendRepository.save(friend);}
}

src\main\java\com\example\campus\service\MessageService.java

package com.example.campus.service;import com.example.campus.dto.SendMessageRequest;
import com.example.campus.entity.Message;
import com.example.campus.repository.MessageRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.List;@Service
public class MessageService {@Autowiredprivate MessageRepository messageRepository;public Message sendMessage(Long senderId, SendMessageRequest req) {Message msg = new Message();msg.setSenderId(senderId);msg.setReceiverId(req.getReceiverId());msg.setContent(req.getContent());msg.setIsRead(false);msg.setCreatedAt(new Timestamp(System.currentTimeMillis()));return messageRepository.save(msg);}public List<Message> listReceivedMessages(Long receiverId) {return messageRepository.findByReceiverId(receiverId);}public List<Message> listConversation(Long userId1, Long userId2) {return messageRepository.findBySenderIdAndReceiverId(userId1, userId2);}public Message markAsRead(Long messageId) {Message msg = messageRepository.findById(messageId).orElseThrow(() -> new RuntimeException("消息不存在"));msg.setIsRead(true);return messageRepository.save(msg);}
}

src\main\java\com\example\campus\service\PostService.java

package com.example.campus.service;import com.example.campus.dto.CreatePostRequest;
import com.example.campus.dto.CreateCommentRequest;
import com.example.campus.entity.Post;
import com.example.campus.entity.Comment;
import com.example.campus.repository.PostRepository;
import com.example.campus.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.List;@Service
public class PostService {@Autowiredprivate PostRepository postRepository;@Autowiredprivate CommentRepository commentRepository;public Post createPost(CreatePostRequest req) {Post post = new Post();post.setUserId(req.getUserId());post.setContent(req.getContent());post.setImageUrl(req.getImageUrl());post.setCreatedAt(new Timestamp(System.currentTimeMillis()));return postRepository.save(post);}public List<Post> listPostsByUser(Long userId) {return postRepository.findByUserId(userId);}public List<Post> listAllPosts() {return postRepository.findAll();}public Comment createComment(CreateCommentRequest req) {Comment comment = new Comment();comment.setPostId(req.getPostId());comment.setUserId(req.getUserId());comment.setContent(req.getContent());comment.setCreatedAt(new Timestamp(System.currentTimeMillis()));return commentRepository.save(comment);}public List<Comment> listCommentsByPost(Long postId) {return commentRepository.findByPostId(postId);}
}

src\main\java\com\example\campus\service\UserService.java

package com.example.campus.service;import com.example.campus.dto.RegisterRequest;
import com.example.campus.dto.LoginRequest;
import com.example.campus.entity.User;
import com.example.campus.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.Optional;@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Autowiredprivate PasswordEncoder passwordEncoder;public User register(RegisterRequest req) {if (userRepository.findByUsername(req.getUsername()).isPresent()) {throw new RuntimeException("用户名已存在");}User user = new User();user.setUsername(req.getUsername());user.setPassword(passwordEncoder.encode(req.getPassword()));user.setRole(req.getRole());user.setEmail(req.getEmail());user.setRealName(req.getRealName());return userRepository.save(user);}public User login(LoginRequest req) {Optional<User> userOpt = userRepository.findByUsername(req.getUsername());if (!userOpt.isPresent()) {throw new RuntimeException("用户不存在");}User user = userOpt.get();if (!passwordEncoder.matches(req.getPassword(), user.getPassword())) {throw new RuntimeException("密码错误");}return user;}public User getUserById(Long id) {return userRepository.findById(id).orElseThrow(() -> new RuntimeException("用户不存在"));}public User updateProfile(Long id, com.example.campus.dto.UpdateProfileRequest req) {User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("用户不存在"));if (req.getEmail() != null) user.setEmail(req.getEmail());if (req.getRealName() != null) user.setRealName(req.getRealName());// 可扩展更多字段return userRepository.save(user);}
}

src\main\resources\application.yml

spring:datasource:url: jdbc:mysql://localhost:3306/campus_social_network?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: rootpassword: your_passworddriver-class-name: com.mysql.cj.jdbc.Driverjpa:hibernate:ddl-auto: updateshow-sql: trueproperties:hibernate:format_sql: truejackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: Asia/Shanghai
server:port: 8080

src\main\resources\schema.sql

CREATE TABLE user (id BIGINT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(50) NOT NULL UNIQUE,password VARCHAR(255) NOT NULL,role ENUM('student', 'teacher') NOT NULL,email VARCHAR(100),real_name VARCHAR(50),created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词