Java全栈项目 - 学生宿舍管理系统
项目介绍
学生宿舍管理系统是一个基于Spring Boot + Vue.js的前后端分离项目,旨在提供完整的宿舍信息管理解决方案。本系统主要面向学校宿舍管理员和学生,实现宿舍分配、维修申请、访客登记等功能。
技术栈
后端
- Spring Boot 2.7.0
- MyBatis Plus
- MySQL 8.0
- Redis
- JWT认证
前端
- Vue.js 3.0
- Element Plus
- Axios
- Vue Router
- Vuex
核心功能
1. 用户管理
- 管理员、宿管、学生多角色登录
- 基于JWT的身份认证
- 权限管理
2. 宿舍管理
- 宿舍楼信息管理
- 房间信息管理
- 床位分配
- 学生入住登记
3. 维修管理
- 维修申请提交
- 维修进度跟踪
- 维修完成确认
- 维修统计分析
4. 访客管理
- 访客登记
- 来访记录查询
- 访客统计
5. 系统监控
- 用户行为日志
- 系统运行状态
- 数据统计报表
数据库设计
主要数据表
-- 用户表
CREATE TABLE sys_user (
id BIGINT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(100),
role VARCHAR(20),
create_time DATETIME
);
-- 宿舍楼表
CREATE TABLE dormitory_building (
id BIGINT PRIMARY KEY,
building_name VARCHAR(50),
floor_count INT,
status VARCHAR(20)
);
-- 房间表
CREATE TABLE room (
id BIGINT PRIMARY KEY,
building_id BIGINT,
room_number VARCHAR(20),
bed_count INT,
used_count INT
);
核心代码展示
后端接口示例
@RestController
@RequestMapping("/api/room")
public class RoomController {
@Autowired
private RoomService roomService;
@GetMapping("/list")
public Result getRoomList(RoomQuery query) {
Page<Room> page = roomService.queryRoomList(query);
return Result.success(page);
}
@PostMapping("/assign")
public Result assignRoom(@RequestBody RoomAssignDTO dto) {
roomService.assignRoom(dto);
return Result.success();
}
}
前端代码示例
<template>
<div class="room-list">
<el-table :data="roomList">
<el-table-column prop="buildingName" label="宿舍楼"/>
<el-table-column prop="roomNumber" label="房间号"/>
<el-table-column prop="bedCount" label="床位数"/>
<el-table-column prop="usedCount" label="已用床位"/>
<el-table-column label="操作">
<template #default="scope">
<el-button @click="handleAssign(scope.row)">分配</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
项目亮点
-
分布式Session管理
- 使用Redis存储session信息
- 支持集群部署
-
高性能查询优化
- MyBatis Plus分页插件
- 合理使用缓存
- SQL优化
-
安全性设计
- 密码加密存储
- JWT令牌认证
- 防XSS攻击
- SQL注入防护
-
前端性能优化
- 组件懒加载
- 图片懒加载
- 路由懒加载
- Gzip压缩
项目部署
-
环境要求
- JDK 1.8+
- MySQL 8.0+
- Redis 6.0+
- Node.js 14+
-
部署步骤
# 后端部署
mvn clean package
java -jar dormitory-0.0.1-SNAPSHOT.jar
# 前端部署
npm install
npm run build
项目总结
通过本项目的开发,不仅实现了学生宿舍管理的信息化、规范化,还在以下方面得到了提升:
- 前后端分离架构的实践经验
- 分布式系统设计能力
- 性能优化经验
- 项目开发规范意识
后续优化方向
- 引入微服务架构
- 添加移动端适配
- 引入消息队列处理异步任务
- 优化数据统计分析功能
- 添加更多自动化功能
本项目作为一个完整的全栈项目,涵盖了实际开发中常见的各类问题和解决方案,是一个非常好的学习和实践案例。
学生宿舍管理系统功能详解
一、用户管理模块
1. 多角色用户体系
管理员角色
- 系统最高权限管理者
- 负责用户账号管理与权限分配
- 可查看所有数据及操作日志
- 系统参数配置权限
宿管角色
- 负责日常宿舍管理工作
- 处理学生入住/调宿/退宿
- 管理访客登记
- 处理维修申请
- 查看所管辖楼栋的统计信息
学生角色
- 查看个人宿舍信息
- 提交维修申请
- 查看通知公告
- 修改个人信息
2. JWT身份认证
@Configuration
public class JwtConfig {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put("username", userDetails.getUsername());
claims.put("role", userDetails.getAuthorities());
return createToken(claims);
}
private String createToken(Map<String, Object> claims) {
return Jwts.builder()
.setClaims(claims)
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
}
3. 权限管理
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/system/config")
public Result getSystemConfig() {
// 系统配置相关操作
}
@PreAuthorize("hasAnyRole('ADMIN', 'MANAGER')")
@GetMapping("/dormitory/stats")
public Result getDormitoryStats() {
// 宿舍统计相关操作
}
二、宿舍管理模块
1. 宿舍楼信息管理
数据结构
CREATE TABLE dormitory_building (
id BIGINT PRIMARY KEY,
building_name VARCHAR(50),
floor_count INT,
room_per_floor INT,
manager_id BIGINT,
contact_phone VARCHAR(20),
build_year INT,
status VARCHAR(20),
remarks TEXT
);
核心功能
@Service
public class BuildingService {
// 添加宿舍楼
public void addBuilding(BuildingDTO dto) {
// 验证数据
validateBuildingData(dto);
// 保存信息
Building building = convertToEntity(dto);
buildingMapper.insert(building);
// 初始化房间信息
initializeRooms(building);
}
// 统计宿舍楼信息
public BuildingStatsVO getBuildingStats(Long buildingId) {
return buildingMapper.selectBuildingStats(buildingId);
}
}
2. 房间信息管理
数据结构
CREATE TABLE room (
id BIGINT PRIMARY KEY,
building_id BIGINT,
room_number VARCHAR(20),
floor INT,
bed_count INT,
used_count INT,
room_type VARCHAR(20),
status VARCHAR(20),
last_check_time DATETIME
);
前端展示
<template>
<div class="room-management">
<el-card>
<div class="room-filters">
<el-select v-model="buildingId" placeholder="选择宿舍楼">
<el-option
v-for="building in buildings"
:key="building.id"
:label="building.name"
:value="building.id"
/>
</el-select>
<el-select v-model="floor" placeholder="选择楼层">
<el-option
v-for="f in floorCount"
:key="f"
:label="`${f}层`"
:value="f"
/>
</el-select>
</div>
<el-table :data="roomList">
<el-table-column prop="roomNumber" label="房间号"/>
<el-table-column prop="bedCount" label="床位数"/>
<el-table-column prop="usedCount" label="已用床位"/>
<el-table-column prop="status" label="状态"/>
<el-table-column label="操作">
<template #default="scope">
<el-button @click="showRoomDetail(scope.row)">详情</el-button>
<el-button @click="handleAssign(scope.row)">分配</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
3. 床位分配
@Service
public class BedAssignmentService {
@Transactional
public void assignBed(BedAssignmentDTO dto) {
// 检查床位是否可用
checkBedAvailability(dto.getRoomId(), dto.getBedNumber());
// 创建床位分配记录
BedAssignment assignment = new BedAssignment();
assignment.setStudentId(dto.getStudentId());
assignment.setRoomId(dto.getRoomId());
assignment.setBedNumber(dto.getBedNumber());
assignment.setStartDate(dto.getStartDate());
// 更新房间使用状态
updateRoomStatus(dto.getRoomId());
// 保存分配记录
bedAssignmentMapper.insert(assignment);
// 发送通知
notificationService.sendAssignmentNotification(dto);
}
}
三、维修管理模块
1. 维修申请
数据结构
CREATE TABLE repair_order (
id BIGINT PRIMARY KEY,
room_id BIGINT,
student_id BIGINT,
repair_type VARCHAR(50),
description TEXT,
images TEXT,
status VARCHAR(20),
create_time DATETIME,
process_time DATETIME,
complete_time DATETIME,
urgency_level VARCHAR(20)
);
申请提交
@PostMapping("/repair/submit")
public Result submitRepair(@RequestBody RepairDTO dto) {
// 验证数据
validateRepairData(dto);
// 处理图片上传
List<String> imageUrls = uploadImages(dto.getImages());
// 创建维修单
RepairOrder order = new RepairOrder();
order.setRoomId(dto.getRoomId());
order.setDescription(dto.getDescription());
order.setImages(String.join(",", imageUrls));
order.setStatus("PENDING");
order.setUrgencyLevel(dto.getUrgencyLevel());
// 保存维修单
repairService.createRepairOrder(order);
return Result.success();
}
2. 维修进度跟踪
@Service
public class RepairTrackingService {
public void updateRepairStatus(Long orderId, String status, String remark) {
// 更新维修单状态
RepairOrder order = repairMapper.selectById(orderId);
order.setStatus(status);
repairMapper.updateById(order);
// 记录维修进度
RepairTracking tracking = new RepairTracking();
tracking.setOrderId(orderId);
tracking.setStatus(status);
tracking.setRemark(remark);
tracking.setOperator(getCurrentUser());
trackingMapper.insert(tracking);
// 发送状态更新通知
if ("COMPLETED".equals(status)) {
notificationService.sendRepairCompleteNotification(order);
}
}
}
3. 维修统计分析
@Service
public class RepairAnalysisService {
// 获取维修类型统计
public List<RepairTypeStats> getRepairTypeStats(Date startDate, Date endDate) {
return repairMapper.selectRepairTypeStats(startDate, endDate);
}
// 获取维修时长分析
public RepairDurationAnalysis getRepairDurationAnalysis() {
return repairMapper.selectRepairDurationAnalysis();
}
// 获取维修满意度统计
public List<RepairSatisfactionStats> getSatisfactionStats() {
return repairMapper.selectSatisfactionStats();
}
}
统计展示
<template>
<div class="repair-statistics">
<!-- 维修类型统计图 -->
<el-card>
<div ref="repairTypeChart" style="height: 400px"></div>
</el-card>
<!-- 维修时长分析 -->
<el-card>
<div ref="durationChart" style="height: 400px"></div>
</el-card>
<!-- 满意度统计 -->
<el-card>
<div ref="satisfactionChart" style="height: 400px"></div>
</el-card>
</div>
</template>
<script>
import * as echarts from 'echarts'
export default {
mounted() {
this.initCharts()
},
methods: {
initCharts() {
// 初始化各类统计图表
this.initRepairTypeChart()
this.initDurationChart()
this.initSatisfactionChart()
}
}
}
</script>
以上是系统主要功能模块的详细设计和实现。每个模块都包含了数据结构设计、后端接口实现和前端界面展示的关键代码。系统通过合理的权限管理和数据流转,确保了各项功能的安全可靠运行。
学生宿舍管理系统功能详解(续)
四、访客管理模块
1. 访客登记
数据结构
-- 访客信息表
CREATE TABLE visitor_record (
id BIGINT PRIMARY KEY,
visitor_name VARCHAR(50),
id_card VARCHAR(18),
phone VARCHAR(20),
visit_purpose VARCHAR(100),
visit_student_id BIGINT,
room_id BIGINT,
check_in_time DATETIME,
expected_leave_time DATETIME,
actual_leave_time DATETIME,
status VARCHAR(20),
remark TEXT,
created_by BIGINT,
created_time DATETIME
);
-- 访客黑名单表
CREATE TABLE visitor_blacklist (
id BIGINT PRIMARY KEY,
visitor_name VARCHAR(50),
id_card VARCHAR(18),
reason TEXT,
start_time DATETIME,
end_time DATETIME,
created_by BIGINT,
created_time DATETIME
);
访客登记功能
@Service
public class VisitorService {
@Transactional
public Result registerVisitor(VisitorDTO dto) {
// 1. 验证访客身份证
if (!validateIdCard(dto.getIdCard())) {
return Result.error("身份证号码不合法");
}
// 2. 检查黑名单
if (checkBlacklist(dto.getIdCard())) {
return Result.error("该访客已被列入黑名单");
}
// 3. 创建访客记录
VisitorRecord record = new VisitorRecord();
BeanUtils.copyProperties(dto, record);
record.setStatus("CHECKED_IN");
record.setCheckInTime(new Date());
// 4. 生成访客二维码
String qrCode = generateVisitorQRCode(record);
record.setQrCode(qrCode);
// 5. 保存记录
visitorMapper.insert(record);
// 6. 发送通知给被访学生
notifyStudent(dto.getVisitStudentId(), record);
return Result.success(record);
}
// 访客离开登记
public void checkOutVisitor(Long recordId) {
VisitorRecord record = visitorMapper.selectById(recordId);
record.setStatus("CHECKED_OUT");
record.setActualLeaveTime(new Date());
visitorMapper.updateById(record);
}
}
前端界面
<template>
<div class="visitor-register">
<el-form
ref="visitorForm"
:model="visitorForm"
:rules="rules"
label-width="100px"
>
<el-form-item label="访客姓名" prop="visitorName">
<el-input v-model="visitorForm.visitorName"/>
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="visitorForm.idCard"/>
</el-form-item>
<el-form-item label="联系电话" prop="phone">
<el-input v-model="visitorForm.phone"/>
</el-form-item>
<el-form-item label="来访目的" prop="visitPurpose">
<el-input type="textarea" v-model="visitorForm.visitPurpose"/>
</el-form-item>
<el-form-item label="被访学生">
<el-select
v-model="visitorForm.visitStudentId"
filterable
remote
:remote-method="searchStudent"
>
<el-option
v-for="student in studentOptions"
:key="student.id"
:label="student.name"
:value="student.id"
/>
</el-select>
</el-form-item>
<el-form-item label="预计离开时间" prop="expectedLeaveTime">
<el-date-picker
v-model="visitorForm.expectedLeaveTime"
type="datetime"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">登记</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
</div>
</template>
2. 来访记录查询
@RestController
@RequestMapping("/api/visitor")
public class VisitorController {
@GetMapping("/records")
public Result getVisitorRecords(VisitorQueryDTO query) {
// 构建查询条件
LambdaQueryWrapper<VisitorRecord> wrapper = new LambdaQueryWrapper<>();
// 添加时间范围条件
if (query.getStartTime() != null && query.getEndTime() != null) {
wrapper.between(VisitorRecord::getCheckInTime,
query.getStartTime(),
query.getEndTime());
}
// 添加访客姓名模糊查询
if (StringUtils.isNotBlank(query.getVisitorName())) {
wrapper.like(VisitorRecord::getVisitorName, query.getVisitorName());
}
// 添加状态条件
if (StringUtils.isNotBlank(query.getStatus())) {
wrapper.eq(VisitorRecord::getStatus, query.getStatus());
}
// 分页查询
Page<VisitorRecord> page = visitorService.page(
new Page<>(query.getPageNum(), query.getPageSize()),
wrapper
);
return Result.success(page);
}
}
3. 访客统计分析
@Service
public class VisitorAnalysisService {
// 获取每日访客统计
public List<DailyVisitorStats> getDailyVisitorStats(Date startDate, Date endDate) {
return visitorMapper.selectDailyVisitorStats(startDate, endDate);
}
// 获取访问目的分布
public List<VisitPurposeStats> getVisitPurposeStats() {
return visitorMapper.selectVisitPurposeStats();
}
// 获取访客时长分布
public List<VisitDurationStats> getVisitDurationStats() {
return visitorMapper.selectVisitDurationStats();
}
// 获取高频访客统计
public List<FrequentVisitorStats> getFrequentVisitorStats() {
return visitorMapper.selectFrequentVisitorStats();
}
}
五、系统监控模块
1. 用户行为日志
数据结构
CREATE TABLE sys_log (
id BIGINT PRIMARY KEY,
user_id BIGINT,
username VARCHAR(50),
operation VARCHAR(50),
method VARCHAR(200),
params TEXT,
ip VARCHAR(64),
location VARCHAR(100),
browser VARCHAR(50),
os VARCHAR(50),
status INTEGER,
error_msg TEXT,
execution_time BIGINT,
create_time DATETIME
);
日志切面实现
@Aspect
@Component
public class LogAspect {
@Autowired
private SysLogService sysLogService;
@Around("@annotation(com.dormitory.annotation.Log)")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
// 执行方法
Object result = point.proceed();
// 保存日志
saveSysLog(point, System.currentTimeMillis() - beginTime);
return result;
}
private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysLog sysLog = new SysLog();
// 获取注解上的描述
Log log = method.getAnnotation(Log.class);
if (log != null) {
sysLog.setOperation(log.value());
}
// 请求的方法名
sysLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
// 请求的参数
sysLog.setParams(JSON.toJSONString(joinPoint.getArgs()));
// 获取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
// 设置IP地址
sysLog.setIp(IPUtils.getIpAddr(request));
// 设置地理位置
sysLog.setLocation(IPUtils.getLocationByIP(sysLog.getIp()));
// 设置用户信息
UserDetails user = SecurityUtils.getCurrentUser();
if (user != null) {
sysLog.setUserId(user.getId());
sysLog.setUsername(user.getUsername());
}
sysLog.setExecutionTime(time);
sysLog.setCreateTime(new Date());
// 保存系统日志
sysLogService.save(sysLog);
}
}
2. 系统运行状态监控
@RestController
@RequestMapping("/api/monitor")
public class SystemMonitorController {
@GetMapping("/server")
public Result getServerInfo() {
ServerInfo info = new ServerInfo();
// CPU信息
info.setCpuInfo(new CpuInfo());
info.getCpuInfo().setUsage(SystemUtil.getCpuUsage());
// 内存信息
MemoryInfo memory = new MemoryInfo();
memory.setTotal(SystemUtil.getMemoryTotal());
memory.setUsed(SystemUtil.getMemoryUsed());
memory.setFree(SystemUtil.getMemoryFree());
info.setMemoryInfo(memory);
// JVM信息
JvmInfo jvm = new JvmInfo();
jvm.setTotal(Runtime.getRuntime().totalMemory());
jvm.setFree(Runtime.getRuntime().freeMemory());
jvm.setMax(Runtime.getRuntime().maxMemory());
jvm.setVersion(System.getProperty("java.version"));
info.setJvmInfo(jvm);
// 磁盘信息
info.setDiskInfo(SystemUtil.getDiskInfo());
return Result.success(info);
}
}
3. 数据统计报表
@Service
public class StatisticsService {
// 宿舍入住率统计
public List<DormitoryOccupancyRate> getDormitoryOccupancyRate() {
return dormitoryMapper.selectOccupancyRate();
}
// 维修工单统计
public RepairOrderStats getRepairOrderStats() {
RepairOrderStats stats = new RepairOrderStats();
stats.setTotalOrders(repairMapper.countTotalOrders());
stats.setPendingOrders(repairMapper.countPendingOrders());
stats.setProcessingOrders(repairMapper.countProcessingOrders());
stats.setCompletedOrders(repairMapper.countCompletedOrders());
return stats;
}
// 访客趋势统计
public List<VisitorTrendStats> getVisitorTrendStats(String timeUnit) {
return visitorMapper.selectVisitorTrendStats(timeUnit);
}
// 导出Excel报表
public void exportExcelReport(HttpServletResponse response) {
// 创建工作簿
XSSFWorkbook workbook = new XSSFWorkbook();
// 创建统计表格
createOccupancySheet(workbook);
createRepairSheet(workbook);
createVisitorSheet(workbook);
// 导出文件
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition",
"attachment;filename=dormitory-report.xlsx");
workbook.write(response.getOutputStream());
}
}
报表展示
<template>
<div class="statistics-dashboard">
<!-- 数据概览卡片 -->
<el-row :gutter="20">
<el-col :span="6">
<el-card shadow="hover">
<div class="stat-card">
<div class="stat-title">总床位数</div>
<div class="stat-value">{{ overview.totalBeds }}</div>
</div>
</el-card>
</el-col>
<!-- 其他统计卡片 -->
</el-row>
<!-- 图表展示区域 -->
<el-row :gutter="20" class="chart-row">
<el-col :span="12">
<el-card>
<div ref="occupancyChart" style="height: 400px"></div>
</el-card>
</el-col>
<el-col :span="12">
<el-card>
<div ref="repairChart" style="height: 400px"></div>
</el-card>
</el-col>
</el-row>
<!-- 导出按钮 -->
<div class="export-actions">
<el-button type="primary" @click="exportExcel">
导出Excel报表
</el-button>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
export default {
data() {
return {
overview: {
totalBeds: 0,
occupiedBeds: 0,
repairOrders: 0,
todayVisitors: 0
},
charts: {
occupancy: null,
repair: null
}
}
},
mounted() {
this.initCharts()
this.loadData()
},
methods: {
initCharts() {
this.charts.occupancy = echarts.init(this.$refs.occupancyChart)
this.charts.repair = echarts.init(this.$refs.repairChart)
// 配置图表选项...
},
async loadData() {
// 加载统计数据...
},
async exportExcel() {
try {
const response = await this.$axios.get('/api/statistics/export', {
responseType: 'blob'
})
const blob = new Blob([response.data], {
type: 'application/vnd.ms-excel'
})
const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'dormitory-report.xlsx'
link.click()
} catch (error) {
this.$message.error('导出失败')
}
}
}
}
</script>
这些模块的实现涵盖了访客管理的完整流程和系统监控的各个方面,包括:
- 访客登记与管理的完整流程
- 基于AOP的系统日志记录
- 服务器状态实时监控
- 多维度的统计分析和报表导出
通过这些功能,可以有效地管理访客流程,监控系统运行状态,并提供决策支持数据。