1. 项目背景与需求分析
高校宿舍维修管理一直是后勤工作中的痛点。记得去年帮某高校做技术咨询时,他们的后勤主任给我看了一摞半人高的纸质维修单,平均响应时间长达72小时。这种传统管理方式存在三个致命缺陷:
- 信息传递滞后:学生需要到宿管处填写纸质表单,再由宿管转交维修部门
- 状态追踪困难:学生无法实时了解维修进度,经常重复报修
- 数据分析缺失:无法统计故障类型分布、维修效率等关键指标
我们设计的这套系统主要解决以下核心问题:
- 建立学生与维修部门的直接沟通渠道
- 实现维修全流程的数字化追踪
- 提供多维度的数据统计分析功能
2. 技术选型与架构设计
2.1 后端技术栈
选择Spring Boot作为后端框架主要基于以下考量:
- 快速迭代:内嵌Tomcat和自动配置机制,调试时只需一个main方法就能启动
- 生态丰富:Spring Data JPA + MyBatis-Plus组合使用,既保留JPA的便捷又满足复杂SQL需求
- 企业级特性:通过Spring Security OAuth2实现RBAC权限控制
java复制// 典型Controller层代码结构
@RestController
@RequestMapping("/repair")
public class RepairController {
@Autowired
private RepairService repairService;
@PostMapping
public Result createOrder(@Valid @RequestBody RepairOrderDTO dto) {
return repairService.createOrder(dto);
}
@GetMapping("/{id}")
@PreAuthorize("hasRole('STUDENT')")
public Result getOrderDetail(@PathVariable Long id) {
return repairService.getOrderDetail(id);
}
}
2.2 前端技术栈
Vue3 + Element Plus的组合带来以下优势:
- 响应式编程:基于Composition API的代码组织更符合逻辑关注点分离原则
- 开发效率:通过Vite构建工具实现秒级热更新
- 组件复用:封装了通用的表单验证、文件上传等业务组件
javascript复制// 典型报修表单组件
export default defineComponent({
setup() {
const form = reactive({
dormNumber: '',
faultType: '',
description: '',
images: []
})
const rules = {
dormNumber: [{ required: true, message: '请输入宿舍号' }],
faultType: [{ required: true, message: '请选择故障类型' }]
}
const onSubmit = async () => {
await repairApi.submitRepair(form)
ElMessage.success('提交成功')
}
return { form, rules, onSubmit }
}
})
2.3 数据库设计
MySQL表设计遵循第三范式的同时做了适当冗余优化:
维修工单表关键字段说明
| 字段 | 类型 | 说明 | 设计考量 |
|---|---|---|---|
| status | TINYINT | 0-待处理 1-处理中 2-已完成 | 使用数值类型提高查询效率 |
| handler_id | VARCHAR | 维修工号 | 建立与staff表的关联 |
| complete_time | DATETIME | 完成时间 | 用于统计维修时长 |
特别注意:status字段使用TINYINT而非ENUM,主要考虑后续可能扩展状态值,且索引效率更高
3. 核心功能实现细节
3.1 维修工单状态机
设计了一个轻量级状态机控制工单流转:
java复制public enum RepairStatus {
PENDING(0) {
@Override
public boolean canTransferTo(RepairStatus status) {
return status == PROCESSING;
}
},
PROCESSING(1) {
@Override
public boolean canTransferTo(RepairStatus status) {
return status == COMPLETED;
}
},
COMPLETED(2);
// 状态转移验证逻辑
public boolean canTransferTo(RepairStatus status) {
return false;
}
}
3.2 文件上传处理
采用阿里云OSS存储维修图片,前端通过Web直传方式减轻服务器压力:
- 后端生成临时凭证
- 前端直接上传到OSS
- 回调服务端记录文件信息
java复制// OSS策略配置示例
public class OssPolicy {
private String accessId;
private String policy;
private String signature;
private String dir; // 按日期分目录存储
private String host;
private long expireTime;
}
3.3 消息通知模块
集成WebSocket实现实时通知:
- 工单状态变更时推送给学生
- 新工单分配给维修人员时触发提醒
- 采用Redis发布订阅模式保证消息可靠性
4. 性能优化实践
4.1 缓存策略
使用Redis二级缓存提升查询性能:
- 热点数据:维修人员信息、宿舍楼数据
- 缓存更新:采用旁路缓存模式
- 过期策略:基础数据12小时,动态数据30分钟
java复制@Cacheable(value = "staff", key = "#staffId")
public StaffVO getStaffInfo(String staffId) {
return staffMapper.selectDetail(staffId);
}
4.2 SQL优化案例
维修记录分页查询优化前:
sql复制SELECT * FROM repair_order
WHERE dorm_number LIKE '%A%'
ORDER BY submit_time DESC
LIMIT 0,10
优化后:
sql复制SELECT r.* FROM repair_order r
JOIN (SELECT id FROM repair_order
WHERE dorm_number LIKE 'A%'
ORDER BY submit_time DESC
LIMIT 0,10) tmp
ON r.id = tmp.id
实测性能提升:当数据量达10万条时,查询耗时从1200ms降至80ms
5. 安全防护措施
5.1 认证授权方案
采用JWT + RBAC模型:
- 学生:提交工单、查看个人工单
- 维修工:接单、更新状态
- 管理员:数据统计、人员管理
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/student/**").hasRole("STUDENT")
.antMatchers("/api/staff/**").hasRole("STAFF")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()));
}
}
5.2 防XSS攻击
前端使用DOMPurify净化输入:
javascript复制import DOMPurify from 'dompurify'
const clean = DOMPurify.sanitize(dirtyInput)
后端统一进行参数过滤:
java复制@RestControllerAdvice
public class XssProtectAdvice implements RequestBodyAdvice {
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage,
MethodParameter parameter, Type targetType) {
return XssUtils.clean(body);
}
}
6. 典型问题排查记录
6.1 工单状态不同步问题
现象:前端显示状态未更新,但数据库已变更
原因:Vue的响应式系统未能检测到数组元素变化
解决方案:
javascript复制// 错误写法
this.orders[index].status = newStatus
// 正确写法
Vue.set(this.orders, index, {...this.orders[index], status: newStatus})
6.2 MyBatis批量插入性能低
问题:插入1000条数据耗时超过10秒
优化方案:
- 使用BatchExecutor
- 调整rewriteBatchedStatements参数
- 分批提交(每500条一个批次)
xml复制<insert id="batchInsert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO repair_detail
(order_id, item_name) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.orderId}, #{item.itemName})
</foreach>
</insert>
7. 部署实践建议
7.1 容器化部署
Docker Compose编排方案:
yaml复制version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql-data:/var/lib/mysql
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
7.2 性能监控配置
Spring Boot Actuator关键端点:
properties复制management.endpoints.web.exposure.include=health,metrics,prometheus
management.metrics.export.prometheus.enabled=true
配合Grafana监控看板:
- JVM内存使用率
- 接口响应时间P99
- 数据库连接池状态
8. 项目演进方向
在实际使用中,我们收集到以下改进建议:
- 移动端适配:开发微信小程序版本,支持扫码报修
- 智能派单:根据维修工位置和专长自动分配工单
- 配件管理:增加维修耗材库存管理模块
- IoT集成:对接智能水电表实现故障预警
特别提醒:数据库连接池配置要根据实际并发量调整,我们初期使用默认配置在高并发时出现了连接泄漏,建议:
properties复制spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.leak-detection-threshold=5000