1. 项目背景与核心价值
高校电动车租赁系统是近年来校园场景下的刚需解决方案。随着校园面积扩大和共享经济普及,学生群体对短途代步工具的需求持续增长。我们团队基于SpringBoot+Vue技术栈实现的这套系统,完整覆盖了车辆管理、用户预约、智能计费、故障报修等核心业务流程。相比市面通用共享平台,专门针对校园封闭环境做了以下优化:
- 采用NFC+二维码双认证机制,兼容校园一卡通系统
- 引入电子围栏技术,自动检测车辆是否驶出校区范围
- 课程表同步功能,优先保障上课时段的车辆供应
- 教职工/学生差异化计费策略
这套系统在技术选型上具有典型教学价值:前端用Vue3+Element Plus实现响应式管理后台,后端采用SpringBoot+MyBatis Plus构建RESTful API,使用Redis处理高并发预约请求,通过Swagger生成标准化接口文档。特别适合作为计算机专业毕业设计案例,涵盖了主流企业级开发技术栈。
2. 技术架构详解
2.1 前后端分离架构设计
系统采用经典的前后端分离模式,通过JSON格式进行数据交互。这种架构的优势在于:
- 开发效率:前后端可以并行开发,只需约定好接口规范
- 性能优化:静态资源由Nginx独立部署,减轻应用服务器压力
- 扩展性:移动端App或小程序可复用现有API接口
技术栈组成:
前端:Vue3 + Vue Router + Pinia + Axios + Element Plus 后端:SpringBoot 2.7 + MyBatis Plus + Redis + MySQL 8.0 工具链:Maven + Git + Swagger + Jenkins2.2 数据库设计要点
数据库共包含12张核心表,这里介绍几个关键设计:
- 车辆信息表(vehicle)
CREATE TABLE `vehicle` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', `plate_no` varchar(20) NOT NULL COMMENT '车牌号', `battery_level` int DEFAULT '100' COMMENT '电量百分比', `status` tinyint DEFAULT '1' COMMENT '状态(1可用 2租赁中 3维修中)', `gps_location` point NOT NULL COMMENT '当前位置坐标', `last_maintain_date` date DEFAULT NULL COMMENT '上次保养日期', PRIMARY KEY (`id`), SPATIAL KEY `idx_location` (`gps_location`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;- 租赁订单表(rent_order)
CREATE TABLE `rent_order` ( `order_no` varchar(32) NOT NULL COMMENT '订单编号', `user_id` bigint NOT NULL COMMENT '用户ID', `vehicle_id` bigint NOT NULL COMMENT '车辆ID', `start_time` datetime NOT NULL COMMENT '开始时间', `end_time` datetime DEFAULT NULL COMMENT '结束时间', `actual_fee` decimal(10,2) DEFAULT NULL COMMENT '实际费用', `pay_status` tinyint DEFAULT '0' COMMENT '支付状态', PRIMARY KEY (`order_no`), KEY `idx_user` (`user_id`), KEY `idx_vehicle` (`vehicle_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;特别注意:空间索引的运用可以大幅提升基于位置的查询效率,这是共享出行类系统的关键优化点。
3. 核心功能实现
3.1 智能计费模块
计费规则采用策略模式实现,便于扩展不同计费方案:
public interface BillingStrategy { BigDecimal calculateFee(RentOrder order); } @Component @Qualifier("studentStrategy") public class StudentBillingStrategy implements BillingStrategy { private static final BigDecimal BASE_RATE = new BigDecimal("1.5"); private static final BigDecimal HOUR_RATE = new BigDecimal("0.8"); @Override public BigDecimal calculateFee(RentOrder order) { long hours = Duration.between(order.getStartTime(), order.getEndTime()).toHours(); return BASE_RATE.add(HOUR_RATE.multiply(new BigDecimal(hours))); } }计费服务通过Spring的自动装配机制灵活切换策略:
@Service public class BillingService { @Autowired @Qualifier("studentStrategy") private BillingStrategy studentStrategy; @Autowired @Qualifier("staffStrategy") private BillingStrategy staffStrategy; public BigDecimal calculateFee(User user, RentOrder order) { return user.isStudent() ? studentStrategy.calculateFee(order) : staffStrategy.calculateFee(order); } }3.2 高并发预约处理
使用Redis实现分布式锁解决超卖问题:
public boolean tryLock(String lockKey, String requestId, long expireTime) { return redisTemplate.opsForValue() .setIfAbsent(lockKey, requestId, expireTime, TimeUnit.SECONDS); } public boolean unlock(String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " + "return redis.call('del', KEYS[1]) " + "else return 0 end"; return redisTemplate.execute( new DefaultRedisScript<>(script, Long.class), Collections.singletonList(lockKey), requestId) == 1; }预约流程关键代码:
public boolean reserveVehicle(Long vehicleId, Long userId) { String lockKey = "lock:vehicle:" + vehicleId; String requestId = UUID.randomUUID().toString(); try { // 获取分布式锁 if (!tryLock(lockKey, requestId, 30)) { throw new RuntimeException("当前车辆正在被其他用户操作"); } // 检查车辆状态 Vehicle vehicle = vehicleMapper.selectById(vehicleId); if (vehicle.getStatus() != VehicleStatus.AVAILABLE) { throw new RuntimeException("车辆不可用"); } // 更新状态 vehicle.setStatus(VehicleStatus.RESERVED); vehicleMapper.updateById(vehicle); // 创建预约记录 Reservation reservation = new Reservation(); reservation.setVehicleId(vehicleId); reservation.setUserId(userId); reservation.setExpireTime(LocalDateTime.now().plusMinutes(15)); reservationMapper.insert(reservation); return true; } finally { unlock(lockKey, requestId); } }4. 系统部署方案
4.1 生产环境配置建议
推荐使用Docker Compose进行容器化部署:
version: '3' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} volumes: - ./mysql/data:/var/lib/mysql - ./mysql/conf:/etc/mysql/conf.d ports: - "3306:3306" redis: image: redis:6 ports: - "6379:6379" volumes: - ./redis/data:/data backend: build: ./backend ports: - "8080:8080" depends_on: - mysql - redis environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/ebike?useSSL=false SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD} frontend: build: ./frontend ports: - "80:80"4.2 Jenkins持续集成配置
pipeline脚本示例:
pipeline { agent any stages { stage('Checkout') { steps { git branch: 'main', url: 'https://github.com/yourrepo/ebike-rental.git' } } stage('Backend Build') { steps { sh 'mvn -f backend/pom.xml clean package' } } stage('Frontend Build') { steps { sh 'npm --prefix frontend install' sh 'npm --prefix frontend run build' } } stage('Docker Build') { steps { sh 'docker-compose build' } } stage('Deploy') { steps { sh 'docker-compose down' sh 'docker-compose up -d' } } } }5. 毕业设计扩展建议
如果想在本系统基础上进行功能扩展,可以考虑以下方向:
- 智能调度算法:基于历史数据预测各区域车辆需求,实现自动调拨
- 电池健康监测:接入IoT设备数据,预测电池更换周期
- 信用评价体系:结合使用行为建立用户信用模型
- 可视化大屏:使用ECharts展示实时运营数据
- 微信小程序端:开发轻量级移动端应用
对于论文写作,建议重点突出:
- 解决的实际痛点问题
- 技术选型的对比分析
- 系统性能优化方案
- 安全防护措施(防SQL注入、XSS攻击等)
6. 常见问题解决方案
6.1 跨域问题处理
后端配置CORS:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .maxAge(3600); } }前端axios配置:
const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000, withCredentials: true })6.2 文件上传大小限制
SpringBoot配置:
# application.properties spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=100MB6.3 慢SQL优化案例
优化前的查询:
SELECT * FROM rent_order WHERE user_id = 123 ORDER BY start_time DESC优化方案:
- 添加复合索引:
ALTER TABLE rent_order ADD INDEX idx_user_time (user_id, start_time) - 改写查询:
SELECT id, order_no, start_time, end_time FROM rent_order WHERE user_id = 123 ORDER BY start_time DESC LIMIT 1007. 项目文档规范
7.1 接口文档示例
使用Swagger UI生成的文档包含:
- 控制器注解:
@RestController @RequestMapping("/api/vehicle") @Tag(name = "车辆管理", description = "电动车相关操作") public class VehicleController { @Autowired private VehicleService vehicleService; @GetMapping("/nearby") @Operation(summary = "查找附近可用车辆") public Result<List<VehicleVO>> findNearbyVehicles( @Parameter(description = "经度") @RequestParam double lng, @Parameter(description = "纬度") @RequestParam double lat, @Parameter(description = "半径(米)") @RequestParam int radius) { return Result.success(vehicleService.findNearby(lng, lat, radius)); } }- 统一响应封装:
public class Result<T> implements Serializable { private int code; private String msg; private T data; public static <T> Result<T> success(T data) { Result<T> result = new Result<>(); result.setCode(200); result.setMsg("success"); result.setData(data); return result; } }7.2 数据库文档规范
建议包含:
- 数据字典(表字段说明)
- E-R关系图
- 索引设计说明
- 分表策略(如有)
- 备份方案
8. 性能优化实战
8.1 缓存策略设计
多级缓存架构:
- 本地缓存(Caffeine):缓存静态数据如配置信息
@Bean public CacheManager cacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager(); cacheManager.setCaffeine(Caffeine.newBuilder() .initialCapacity(100) .maximumSize(1000) .expireAfterWrite(10, TimeUnit.MINUTES)); return cacheManager; }- Redis缓存:缓存热点数据如车辆状态
@Cacheable(value = "vehicle", key = "#id") public Vehicle getById(Long id) { return vehicleMapper.selectById(id); }- 数据库缓存:合理使用MySQL查询缓存
8.2 线程池优化
自定义线程池配置:
@Configuration public class ThreadPoolConfig { @Bean("taskExecutor") public ThreadPoolTaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(50); executor.setQueueCapacity(200); executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix("async-task-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }异步任务示例:
@Async("taskExecutor") public void asyncUpdateVehicleStatus(Long vehicleId, VehicleStatus status) { // 状态更新逻辑 }9. 安全防护措施
9.1 SQL注入防护
- 始终使用预编译语句:
@Select("SELECT * FROM user WHERE username = #{username} AND password = #{password}") User authenticate(@Param("username") String username, @Param("password") String password);- 输入参数过滤:
public static String filterSQL(String input) { return input.replaceAll("([';]+|(--)+)", ""); }9.2 XSS防护
前端过滤:
function escapeHtml(unsafe) { return unsafe .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'"); }后端过滤:
public static String cleanXSS(String value) { return HtmlUtils.htmlEscape(value); }10. 项目实战经验
10.1 开发环境搭建技巧
- 使用Lombok减少样板代码:
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class User { private Long id; private String username; private UserType type; }- 配置热部署:
<!-- pom.xml --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency>10.2 调试技巧
接口调试工具链:
- Postman:接口测试
- Arthas:Java诊断工具
- Vue DevTools:前端调试
日志配置建议:
# application-dev.properties logging.level.root=INFO logging.level.com.yourpackage=DEBUG logging.file.name=logs/application.log- 常用Linux排查命令:
# 查看Java进程 ps -ef | grep java # 查看端口占用 netstat -tunlp | grep 8080 # 实时日志查看 tail -f logs/application.log