1. 项目概述:基于Web的美食探店平台设计与实现
作为一名拥有10年全栈开发经验的工程师,我经常被问到如何从零开始构建一个完整的Web应用。今天要分享的这个基于Spring Boot的美食探店平台,是我指导过2000+学生完成的毕业设计项目中比较典型的一个案例。这个项目不仅涵盖了企业级应用开发的核心技术栈,还融入了许多我在实际工作中积累的优化技巧。
这个平台本质上是一个连接美食爱好者与餐厅的双向服务系统。用户端提供餐厅搜索、点评、收藏等功能,商家端则支持店铺信息管理、促销活动发布等操作。技术架构上,我们采用前后端分离模式,后端使用Spring Boot+MyBatis Plus,前端选用Vue.js,数据库采用MySQL 8.0。这种组合既保证了开发效率,又能满足毕业设计对技术深度的要求。
2. 系统架构设计
2.1 MVC架构实现
项目采用经典的MVC模式分层,但我们在标准三层架构基础上做了优化扩展:
视图层(View):
- 使用Vue 3组合式API开发
- 采用Element Plus组件库保证UI一致性
- 实现真正的动静分离,前端独立部署
- 加入Axios拦截器统一处理HTTP请求
javascript复制// 示例:封装后的API请求方法
export const getRestaurantList = (params) => {
return request({
url: '/api/restaurants',
method: 'get',
params
})
}
控制层(Controller):
- 使用@RestController注解
- 统一返回Result封装对象
- 全局异常处理@ControllerAdvice
- 参数校验使用@Validated
java复制@RestController
@RequestMapping("/api/restaurants")
public class RestaurantController {
@Autowired
private RestaurantService restaurantService;
@GetMapping
public Result<List<RestaurantVO>> list(@Valid RestaurantQuery query) {
return Result.success(restaurantService.queryRestaurants(query));
}
}
服务层(Service):
- 接口与实现分离
- 事务管理@Transactional
- 业务逻辑封装
- DTO/VO对象转换
持久层(Mapper):
- MyBatis Plus增强
- 自定义SQL写在XML中
- 动态SQL生成
- 二级缓存配置
2.2 技术栈选型解析
后端技术决策:
-
Spring Boot 2.7.x
- 内嵌Tomcat简化部署
- 自动配置减少样板代码
- Starter依赖一键集成
- Actuator监控端点
-
MyBatis Plus 3.5.x
- 通用Mapper减少CRUD代码
- Lambda表达式查询
- 分页插件自动处理
- 乐观锁支持
前端技术决策:
-
Vue 3 + Vite
- 组合式API代码组织更好
- 按需编译加快开发速度
- Pinia状态管理
- Vue Router路由守卫
-
Element Plus
- 丰富的预制组件
- 主题定制能力
- 移动端适配
- 国际化支持
数据库选型:
- MySQL 8.0
- JSON类型支持
- 窗口函数
- CTE公用表表达式
- 更好的索引性能
3. 核心功能实现
3.1 餐厅搜索模块
搜索功能采用Elasticsearch实现全文检索,同时支持多种筛选条件:
java复制public Page<Restaurant> search(RestaurantSearchDTO dto) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 关键词匹配
if (StringUtils.isNotBlank(dto.getKeyword())) {
queryBuilder.withQuery(QueryBuilders.multiMatchQuery(dto.getKeyword(),
"name", "description", "tags"));
}
// 地理距离筛选
if (dto.getLat() != null && dto.getLng() != null) {
queryBuilder.withFilter(QueryBuilders.geoDistanceQuery("location")
.point(dto.getLat(), dto.getLng())
.distance(dto.getDistance(), DistanceUnit.KILOMETERS));
}
// 分页处理
queryBuilder.withPageable(PageRequest.of(dto.getPage(), dto.getSize()));
return elasticsearchRestTemplate.search(queryBuilder.build(), Restaurant.class);
}
搜索优化技巧:
- 使用IK分词器优化中文分词
- 对名称字段设置boost权重
- 异步索引更新策略
- 搜索结果缓存处理
3.2 用户点评系统
点评功能设计考虑了防刷机制和内容安全:
java复制@Transactional
public Review addReview(ReviewDTO dto) {
// 检查用户当日点评次数
String todayKey = "user:review:" + dto.getUserId() + ":" + LocalDate.now();
long count = redisTemplate.opsForValue().increment(todayKey);
if (count > MAX_REVIEW_PER_DAY) {
throw new BusinessException("今日点评次数已达上限");
}
// 内容安全检测
if (sensitiveFilter.contains(dto.getContent())) {
throw new BusinessException("内容包含敏感词");
}
// 保存点评
Review review = convertToEntity(dto);
reviewMapper.insert(review);
// 更新餐厅评分
updateRestaurantRating(review.getRestaurantId());
return review;
}
防刷策略:
- Redis计数器限制单日操作
- 设备指纹识别
- 行为模式分析
- 验证码二次确认
4. 数据库设计实践
4.1 核心表结构
餐厅表(restaurant):
sql复制CREATE TABLE `restaurant` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '餐厅名称',
`address` varchar(255) NOT NULL,
`phone` varchar(20) DEFAULT NULL,
`description` text,
`avg_rating` decimal(3,1) DEFAULT '0.0' COMMENT '平均评分',
`location` point NOT NULL COMMENT '地理位置',
`opening_hours` json DEFAULT NULL COMMENT '营业时间',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
SPATIAL KEY `idx_location` (`location`),
FULLTEXT KEY `idx_search` (`name`,`description`,`tags`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
点评表(review):
sql复制CREATE TABLE `review` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`restaurant_id` bigint NOT NULL,
`content` text NOT NULL,
`rating` tinyint NOT NULL COMMENT '1-5星评分',
`images` json DEFAULT NULL COMMENT '图片URL数组',
`is_anonymous` tinyint(1) DEFAULT '0',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_restaurant` (`restaurant_id`),
KEY `idx_user` (`user_id`),
CONSTRAINT `fk_review_restaurant` FOREIGN KEY (`restaurant_id`) REFERENCES `restaurant` (`id`),
CONSTRAINT `fk_review_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
4.2 性能优化实践
-
索引策略:
- 地理位置使用SPATIAL索引
- 搜索字段使用FULLTEXT索引
- 外键字段建立普通索引
- 组合索引遵循最左前缀原则
-
分表方案:
- 点评数据按月分表
- 使用ShardingSphere实现透明访问
- 历史数据冷热分离
-
缓存设计:
- 餐厅详情使用Redis缓存
- 采用多级缓存策略
- 缓存失效机制设计
5. 安全防护体系
5.1 认证授权方案
采用JWT+Spring Security实现安全控制:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
}
安全增强措施:
- JWT设置合理过期时间
- 敏感操作需要二次验证
- 密码加密存储
- 接口防重放攻击
5.2 数据安全防护
-
SQL注入防护:
- 使用预编译语句
- MyBatis参数绑定
- 禁止拼接SQL
-
XSS防护:
- 前端DOMPurify过滤
- 后端Jackson转义
- CSP内容安全策略
-
CSRF防护:
- 同源策略检查
- 关键操作验证Referer
- 敏感操作验证码
6. 部署与监控
6.1 容器化部署
使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
elasticsearch:
image: elasticsearch:7.17.0
environment:
- discovery.type=single-node
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
- elasticsearch
frontend:
build: ./frontend
ports:
- "80:80"
volumes:
mysql_data:
6.2 监控方案
-
Spring Boot Actuator
- 健康检查端点
- 指标监控
- 自定义指标
-
Prometheus + Grafana
- JVM监控
- 接口响应时间
- 数据库连接池
-
ELK日志系统
- 日志收集
- 异常告警
- 请求追踪
7. 项目开发经验总结
在实际指导学生完成这个项目的过程中,我总结了几个关键经验:
-
接口设计先行:
使用Swagger/OAS3先定义接口规范,前后端并行开发。我们采用OpenAPI 3.0规范编写接口文档,使用SpringDoc自动生成文档页面。 -
版本控制策略:
采用Git Flow工作流,feature分支开发,PR合并到develop分支,release分支发布。每个功能点保持小颗粒度提交。 -
持续集成实践:
配置GitHub Actions实现自动化:- 代码风格检查
- 单元测试执行
- 构建产物生成
- 容器镜像打包
-
性能优化技巧:
- Nginx启用Gzip压缩
- 静态资源CDN加速
- 数据库连接池调优
- 缓存穿透防护
-
异常处理规范:
定义统一的错误码体系,全局异常处理器捕获各类异常,返回结构化的错误信息。
java复制@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusinessException(BusinessException e) {
return Result.fail(e.getCode(), e.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Void> handleValidationException(MethodArgumentNotValidException e) {
String message = e.getBindingResult()
.getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return Result.fail(ErrorCode.PARAM_ERROR, message);
}
}
这个美食探店平台项目涵盖了企业级应用开发的完整流程,从需求分析、技术选型、架构设计到具体实现和部署运维。对于计算机相关专业的同学来说,通过实践这样一个项目,可以系统性地掌握现代Web开发的完整技术栈,为未来的职业发展打下坚实基础。