毕业设计实战:基于Spring Boot的校园周边美食探索及分享平台设计与实现

45 阅读18分钟

一、项目背景:为什么需要校园周边美食探索及分享平台?

在高校校园生活中,美食消费是学生日常需求的重要组成部分——学生既希望快速获取校园周边美食信息,又渴望与同学分享优质美食体验。传统美食获取方式存在信息分散、缺乏互动、筛选困难等痛点:学生往往依赖口口相传或线下探店获取美食信息,不仅效率低,还难以精准匹配口味偏好;商家也面临校园客群触达难、推广成本高的问题。

随着"互联网+校园服务"模式的普及,基于Spring Boot的校园周边美食探索及分享平台成为解决这些痛点的创新方案。系统采用B/S架构,通过信息化手段实现"学生探索分享-商家展示推广-管理员高效管理"的三方联动,既为学生提供直观、便捷的美食信息获取与互动渠道,也为商家降低推广成本、精准触达校园客群。本毕业设计以高校师生的美食消费需求为核心,打造功能完善、体验流畅的校园美食服务平台,填补校园周边美食信息化服务的空白。

二、核心技术栈:美食平台的全链路开发工具

项目以"高易用性、强互动性、低维护成本"为目标,采用成熟稳定的Java Web开发技术栈,确保系统能适配校园网络环境与用户使用习惯:

技术模块具体工具/技术核心作用
后端框架Spring Boot 2.x快速搭建后端服务,简化配置,支持高效开发与维护
数据库MySQL 8.0存储用户信息、美食数据、好友关系、收藏记录等核心数据
前端技术JSP + HTML5 + CSS3 + JavaScript构建直观友好的用户界面,实现美食展示、互动分享等功能
架构模式B/S架构支持跨设备访问,学生、商家、管理员通过浏览器即可使用系统
开发工具MyEclipse + NavicatMyEclipse编写代码,Navicat可视化管理MySQL数据库
服务器Tomcat 9.0部署Web应用,处理用户请求与数据交互
核心特性图片上传 + 互动评论 + 收藏功能实现美食图片展示、用户评论互动、个性化收藏管理

三、项目全流程:7步实现校园周边美食探索及分享平台

3.1 第一步:需求分析——明确系统核心价值

传统校园美食服务存在"信息零散、互动缺失、管理低效"三大痛点,本系统聚焦"便捷探索、社交分享、高效管理",核心需求分为功能性与非功能性两类:

3.1.1 功能性需求

  1. 三角色权限管理
    • 管理员:用户管理(学生账号维护)、美食鉴赏管理(内容审核)、系统管理(配置维护)、数据监控(平台使用统计);
    • 学生用户:美食探索(浏览周边美食)、美食分享(发布鉴赏内容)、社交互动(添加好友、评论点赞)、个性化管理(收藏、个人信息维护);
    • 间接服务商家:通过学生分享间接展示美食,获取校园客群关注(后续可扩展商家入驻功能)。
  2. 核心美食服务功能
    • 美食鉴赏模块:展示美食名称、类别、价格、店铺位置、推荐指数、用户评价等信息,支持图片查看;
    • 社交互动模块:添加好友、评论美食、点赞分享,形成校园美食社交圈;
    • 个性化管理模块:收藏心仪美食、维护个人信息、查看历史互动记录;
    • 搜索筛选模块:按美食类别、推荐指数、价格范围筛选,快速找到目标美食。
  3. 辅助管理功能
    • 内容审核:管理员审核学生发布的美食鉴赏内容,确保信息真实合规;
    • 用户维护:管理员管理学生账号,处理账号异常问题;
    • 系统配置:维护平台基础参数,如轮播图、分类标签等。

3.1.2 非功能性需求

  • 易用性:界面简洁直观,学生无需培训即可熟练使用,核心操作(如浏览美食、发布鉴赏)不超过3步;
  • 响应速度:页面加载时间≤2秒,美食图片加载优化,适配校园网络环境;
  • 稳定性:支持同时在线1000+学生访问,无卡顿、崩溃问题;
  • 可扩展性:预留商家入驻、在线订餐接口,便于后续功能升级。

3.2 第二步:系统设计——构建前后端架构

系统采用MVC设计模式,实现"视图-控制器-模型"分离,确保代码可维护性与功能扩展性:

3.2.1 系统总体架构

  1. 表现层(View层)
    • 前台首页:面向所有用户,展示热门美食、推荐鉴赏、轮播图等;
    • 学生后台:学生专属界面,包含个人中心、美食鉴赏管理、好友管理、收藏管理;
    • 管理员后台:管理员操作界面,包含用户管理、美食审核、系统配置、数据统计。
  2. 业务逻辑层(Controller层)
    • 核心业务:用户登录注册、美食信息CRUD、好友关系管理、收藏操作、评论互动;
    • 业务规则:用户权限校验、美食内容审核逻辑、数据合法性校验。
  3. 数据访问层(Model层)
    • 数据持久化:通过MyBatis实现数据库操作,简化SQL编写;
    • 事务控制:确保关键操作(如发布美食鉴赏、添加好友)的数据一致性。

3.2.2 核心数据库设计

系统设计6张核心业务表,覆盖用户、美食、社交、系统配置全场景,确保数据完整性与关联性:

表名核心字段作用
users(用户表)id、username(用户名)、password(密码)、role(角色)、addtime(新增时间)存储管理员与学生账号信息,区分角色权限
yonghu(学生信息表)id、yonghuming(用户名)、xingming(姓名)、shouji(手机)、youxiang(邮箱)、shenfenzheng(身份证)、zhaopian(照片)存储学生详细个人信息
meishijianshang(美食鉴赏表)id、fabushijian(发布时间)、meishimingcheng(美食名称)、meishileibie(美食类别)、meishijieshao(美食介绍)、shangpusuozaidi(店铺位置)、tuijianzhishu(推荐指数)、meishizhaopian(美食照片)、shangpinjiage(价格)存储学生发布的美食鉴赏内容
wodehaoyou(好友表)id、yonghuming(用户名)、xingming(好友姓名)、tianjiashijian(添加时间)存储学生好友关系数据
collections(收藏表)id、yonghuming(用户名)、meishi_id(美食ID)、shoucang_time(收藏时间)存储学生收藏的美食记录
config(系统配置表)id、name(配置名称)、value(配置值)存储系统基础配置,如轮播图地址、分类标签

3.3 第三步:后端核心功能实现——Spring Boot架构

基于Spring Boot框架实现后端核心业务逻辑,重点解决"美食信息管理"与"用户互动"功能,确保操作流畅、数据安全:

3.3.1 美食鉴赏功能实现

@RestController
@RequestMapping("/api/meishijianshang")
public class MeiShiJianShangController {
    
    @Autowired
    private MeiShiJianShangService meiShiService;
    
    @Autowired
    private YongHuService yongHuService;
    
    /**
     * 获取美食鉴赏列表(支持筛选)
     * @param meishileibie 美食类别
     * @param tuijianzhishu 最低推荐指数
     * @return 筛选后的美食列表
     */
    @GetMapping("/list")
    public ResponseEntity<List<MeiShiJianShang>> getMeiShiList(
            @RequestParam(required = false) String meishileibie,
            @RequestParam(required = false, defaultValue = "1") Integer tuijianzhishu) {
        try {
            // 构建查询条件
            Map<String, Object> condition = new HashMap<>();
            if (StringUtils.hasText(meishileibie)) {
                condition.put("meishileibie", meishileibie);
            }
            condition.put("tuijianzhishu", tuijianzhishu);
            
            // 调用服务层查询数据
            List<MeiShiJianShang> meiShiList = meiShiService.getListByCondition(condition);
            return ResponseEntity.ok(meiShiList);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.internalServerError().body(null);
        }
    }
    
    /**
     * 发布美食鉴赏
     * @param meiShiDTO 美食鉴赏数据(包含名称、类别、介绍等)
     * @param request 获取当前登录用户
     * @return 发布结果
     */
    @PostMapping("/publish")
    public ResponseEntity<String> publishMeiShi(
            @RequestBody MeiShiJianShangDTO meiShiDTO,
            HttpServletRequest request) {
        try {
            // 1. 校验当前用户是否登录
            String username = (String) request.getSession().getAttribute("username");
            if (StringUtils.isEmpty(username)) {
                return ResponseEntity.badRequest().body("请先登录");
            }
            
            // 2. 校验学生信息是否存在
            YongHu yongHu = yongHuService.getByUsername(username);
            if (yongHu == null) {
                return ResponseEntity.badRequest().body("用户信息不存在");
            }
            
            // 3. 转换DTO为实体类,补充发布信息
            MeiShiJianShang meiShi = new MeiShiJianShang();
            BeanUtils.copyProperties(meiShiDTO, meiShi);
            meiShi.setFabushijian(System.currentTimeMillis()); // 发布时间(时间戳)
            meiShi.setYonghuming(username); // 发布者用户名
            meiShi.setXingming(yongHu.getXingming()); // 发布者姓名
            meiShi.setTuijianzhishu(meiShiDTO.getTuijianzhishu() == null ? 3 : meiShiDTO.getTuijianzhishu()); // 默认3星推荐
            
            // 4. 调用服务层保存数据
            boolean success = meiShiService.save(meiShi);
            if (success) {
                return ResponseEntity.ok("美食鉴赏发布成功");
            } else {
                return ResponseEntity.internalServerError().body("发布失败,请重试");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.internalServerError().body("系统异常,发布失败");
        }
    }
    
    /**
     * 点赞美食鉴赏
     * @param id 美食ID
     * @return 点赞结果
     */
    @PostMapping("/like/{id}")
    public ResponseEntity<String> likeMeiShi(@PathVariable Long id) {
        try {
            // 校验美食是否存在
            MeiShiJianShang meiShi = meiShiService.getById(id);
            if (meiShi == null) {
                return ResponseEntity.badRequest().body("美食不存在");
            }
            
            // 增加点赞数(实际项目可优化为用户唯一点赞,避免重复)
            meiShi.setDianzanshu(meiShi.getDianzanshu() == null ? 1 : meiShi.getDianzanshu() + 1);
            meiShiService.updateById(meiShi);
            
            return ResponseEntity.ok("点赞成功,当前点赞数:" + meiShi.getDianzanshu());
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.internalServerError().body("点赞失败");
        }
    }
}

3.3.2 好友管理功能实现

@Service
@Transactional
public class WoDeHaoYouService {
    
    @Autowired
    private WoDeHaoYouMapper haoYouMapper;
    
    @Autowired
    private YongHuMapper yongHuMapper;
    
    /**
     * 添加好友
     * @param username 当前用户名
     * @param friendUsername 好友用户名
     * @return 添加结果
     */
    public String addFriend(String username, String friendUsername) {
        // 1. 校验当前用户与好友是否存在
        YongHu currentUser = yongHuMapper.getByUsername(username);
        YongHu friendUser = yongHuMapper.getByUsername(friendUsername);
        if (currentUser == null) {
            return "当前用户不存在";
        }
        if (friendUser == null) {
            return "好友用户不存在";
        }
        
        // 2. 校验是否已添加该好友
        WoDeHaoYou existFriend = haoYouMapper.getByUserAndFriend(username, friendUsername);
        if (existFriend != null) {
            return "已添加该好友,无需重复添加";
        }
        
        // 3. 保存好友关系
        WoDeHaoYou haoYou = new WoDeHaoYou();
        haoYou.setYonghuming(username);
        haoYou.setXingming(friendUser.getXingming());
        haoYou.setTianjiashijian(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        haoYouMapper.insert(haoYou);
        
        return "好友添加成功";
    }
    
    /**
     * 获取好友列表
     * @param username 当前用户名
     * @return 好友列表
     */
    public List<WoDeHaoYou> getFriendList(String username) {
        return haoYouMapper.getByUsername(username);
    }
    
    /**
     * 删除好友
     * @param id 好友记录ID
     * @param username 当前用户名
     * @return 删除结果
     */
    public boolean deleteFriend(Long id, String username) {
        // 校验该好友记录是否属于当前用户(防止越权删除)
        WoDeHaoYou haoYou = haoYouMapper.selectById(id);
        if (haoYou == null || !haoYou.getYonghuming().equals(username)) {
            return false;
        }
        
        // 执行删除
        haoYouMapper.deleteById(id);
        return true;
    }
}

3.4 第四步:多角色权限实现——精细化的权限控制

基于Session与角色标识实现权限管理,确保不同角色只能访问对应功能,保障系统数据安全:

3.4.1 管理员权限(role=管理员)

  • 用户管理:查看所有学生账号列表,支持新增、修改、删除学生账号,维护用户状态;
  • 美食审核:审核学生发布的美食鉴赏内容,对违规内容进行驳回或删除;
  • 系统配置:管理前台轮播图(上传、删除、调整顺序)、维护美食类别标签;
  • 数据统计:查看平台使用数据(如活跃用户数、美食发布量、互动次数)。

3.4.2 学生权限(role=学生)

  • 前台操作:浏览美食列表、查看美食详情、评论点赞、搜索筛选美食;
  • 个人管理:维护个人信息(修改姓名、手机、邮箱、上传头像)、修改登录密码;
  • 内容发布:发布美食鉴赏(上传图片、填写详情)、编辑/删除自己发布的内容;
  • 社交互动:添加/删除好友、查看好友列表、与好友分享美食;
  • 个性化收藏:收藏心仪美食、查看收藏列表、取消收藏。

3.4.3 权限拦截实现

通过过滤器拦截未登录请求与越权请求,确保权限控制生效:

@Component
public class AuthFilter implements Filter {
    
    // 无需登录即可访问的路径
    private static final List<String> NO_LOGIN_PATHS = Arrays.asList("/login", "/register", "/index", "/api/meishijianshang/list");
    
    // 管理员专属路径
    private static final List<String> ADMIN_PATHS = Arrays.asList("/admin/", "/api/admin/");
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String url = httpRequest.getRequestURI();
        
        // 1. 放行无需登录的路径
        if (NO_LOGIN_PATHS.stream().anyMatch(path -> url.startsWith(path))) {
            chain.doFilter(request, response);
            return;
        }
        
        // 2. 校验是否登录
        String username = (String) httpRequest.getSession().getAttribute("username");
        String role = (String) httpRequest.getSession().getAttribute("role");
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(role)) {
            // 未登录,重定向到登录页
            httpResponse.sendRedirect("/login");
            return;
        }
        
        // 3. 校验管理员权限(访问管理员路径需角色为"管理员")
        if (ADMIN_PATHS.stream().anyMatch(path -> url.startsWith(path)) && !"管理员".equals(role)) {
            // 无管理员权限,返回403
            httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
            httpResponse.getWriter().write("无权限访问,请联系管理员");
            return;
        }
        
        // 4. 权限校验通过,放行请求
        chain.doFilter(request, response);
    }
}

3.5 第五步:前端界面实现——直观友好的校园美食界面

基于JSP + Bootstrap构建响应式界面,适配电脑、平板等设备,确保学生使用体验流畅:

3.5.1 前台首页(面向所有用户)

  • 顶部导航栏:包含"首页"、"美食鉴赏"、"我的好友"、"个人中心"、"后台管理"(登录后显示对应角色入口);
  • 轮播图区域:展示热门美食图片,点击跳转至对应美食详情;
  • 美食推荐区:按推荐指数排序展示美食,包含美食图片、名称、价格、店铺位置、推荐星数,支持快速查看详情;
  • 分类筛选区:左侧按美食类别(如快餐、奶茶、烧烤、小吃)筛选,右侧按价格、推荐指数二次筛选。

3.5.2 学生后台界面

  • 个人中心:左侧导航栏(个人信息、美食管理、好友管理、收藏管理),右侧展示对应功能内容;
    • 个人信息:显示姓名、手机、邮箱等,支持上传头像、修改信息;
    • 美食管理:展示自己发布的美食鉴赏列表,支持编辑、删除、查看评论;
    • 好友管理:展示好友列表,支持添加好友、删除好友、查看好友发布的美食;
    • 收藏管理:展示收藏的美食,支持取消收藏、快速跳转至美食详情。
  • 美食发布界面:表单式设计,包含美食名称(输入框)、类别(下拉选择)、介绍(文本域)、店铺位置(输入框)、价格(输入框)、图片(上传按钮)、推荐指数(星级选择),提交后等待审核(若开启审核功能)。

3.5.3 管理员后台界面

  • 数据看板:顶部展示关键数据(学生用户数、美食总数、好友关系数、收藏数),直观了解平台运营情况;
  • 用户管理:表格展示所有学生账号,支持按用户名搜索,操作列包含"编辑"、"删除"、"重置密码";
  • 美食管理:展示所有美食鉴赏内容,支持按发布时间、推荐指数筛选,操作列包含"审核通过"、"驳回"、"删除";
  • 系统配置:轮播图管理(上传图片、设置跳转链接、调整顺序)、美食类别管理(新增、编辑、删除类别)。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

3.6 第六步:系统测试——确保平台稳定可用

通过全面测试验证系统功能、性能与兼容性,测试环境适配校园常见配置:

  • 硬件环境:Inter Core I7-4710MQ处理器、4GB内存、1TB硬盘;
  • 软件环境:Windows 10操作系统、MySQL 8.0数据库、Tomcat 9.0服务器、Chrome/Firefox/Edge浏览器。

3.6.1 功能测试

设计30组核心测试用例,覆盖用户登录、美食发布、好友互动等关键场景,确保功能正常:

测试场景测试步骤预期结果实际结果是否通过
学生登录1. 访问登录页;2. 输入正确用户名/密码;3. 点击登录登录成功,跳转至首页,显示用户名与预期一致
发布美食鉴赏1. 登录学生账号;2. 进入"美食管理";3. 填写美食信息并上传图片;4. 提交发布成功,列表显示新发布内容与预期一致
添加好友1. 进入"好友管理";2. 输入好友用户名;3. 点击"添加"添加成功,好友列表显示新好友与预期一致
管理员审核美食1. 登录管理员账号;2. 进入"美食管理";3. 选择待审核内容;4. 点击"审核通过"美食状态变为"已审核",前台可查看与预期一致
收藏美食1. 浏览美食详情;2. 点击"收藏"按钮收藏成功,"我的收藏"列表显示该美食与预期一致

3.6.2 性能与兼容性测试

  • 性能测试:模拟500名学生同时在线浏览美食、发布内容,系统响应时间≤1.5秒,无数据丢失或卡顿;
  • 兼容性测试:在Chrome、Firefox、Edge浏览器中测试,界面显示正常,功能无异常;
  • 稳定性测试:连续运行72小时,监控CPU使用率(≤60%)、内存占用(≤50%),无崩溃或内存泄漏。

3.7 第七步:问题排查与优化——提升平台体验

开发过程中遇到的典型问题及解决方案,确保系统更贴合校园实际使用场景:

  1. 美食图片加载慢

    • 问题:学生上传的美食图片尺寸大,导致列表加载卡顿;
    • 解决方案:实现图片压缩功能(上传时自动压缩至800px以内),采用懒加载技术(滚动到可视区域再加载图片),加载速度提升60%。
  2. 好友添加重复校验

    • 问题:初始版本未校验重复添加,导致好友列表出现重复数据;
    • 解决方案:在服务层添加"按用户名+好友用户名"的唯一校验,添加前查询是否已存在该好友关系,避免重复。
  3. 管理员权限越权访问

    • 问题:学生账号可通过直接输入URL访问管理员后台;
    • 解决方案:添加权限过滤器,校验请求路径与角色匹配性,非管理员角色访问管理员路径时返回403,确保权限安全。
  4. 美食筛选效率低

    • 问题:初始版本筛选时全表扫描,数据量大时筛选卡顿;
    • 解决方案:在meishijianshang表的meishileibie(美食类别)、tuijianzhishu(推荐指数)字段添加索引,筛选时间从1.2秒优化至0.3秒。

四、毕业设计复盘:经验与教训

4.1 开发过程中的挑战

  1. 需求边界把控:初期想加入"在线订餐"功能,但考虑到开发时间与复杂度,最终聚焦"探索与分享"核心需求,避免功能冗余;
  2. 用户体验优化:学生对界面操作流畅度要求高,需反复调整按钮位置、表单布局,通过校园小范围测试收集反馈,迭代优化3次;
  3. 数据关联设计:美食、用户、好友、收藏之间的关联关系需清晰,初期因表结构设计不合理导致查询效率低,后期重构数据库索引与关联逻辑;
  4. 权限控制细节:需考虑"学生不能删除他人美食"、"管理员不能越权修改学生个人信息"等细节,避免权限漏洞。

4.2 给学弟学妹的建议

  1. 需求聚焦:毕业设计时间有限,优先实现核心功能,避免"大而全"导致"全而不精",后期可预留扩展接口;
  2. 技术选型务实:选择自己熟悉的技术栈(如本项目用Spring Boot而非更复杂的微服务),确保能按时完成并 debug;
  3. 重视测试:不要等到开发完成再测试,边开发边写测试用例,提前发现问题(如权限漏洞、数据异常),减少后期返工;
  4. 文档同步:同步编写技术文档(如数据库设计文档、接口说明),既便于自己梳理思路,也方便答辩时展示项目完整性;
  5. 结合实际场景:校园项目需贴合师生使用习惯(如界面简洁、操作简单),可通过问卷或访谈收集真实需求,让项目更有实用价值。

五、项目资源与未来展望

5.1 项目核心资源

本项目提供完整的开发资源包,可直接用于毕业设计或校园实际部署:

  • 后端源码:完整的Spring Boot项目(包含Controller、Service、Mapper层代码);
  • 前端资源:JSP页面、CSS/JS文件、图片资源,支持直接部署;
  • 数据库脚本:MySQL建表语句、测试数据(含学生账号、美食示例);
  • 部署指南:详细的环境配置、项目部署步骤,新手可快速上手;
  • 答辩PPT模板:包含项目背景、技术栈、功能演示、复盘总结,适配毕业设计答辩。

5.2 系统扩展方向

  1. 商家入驻功能:新增商家角色,支持商家自主发布美食信息、设置优惠活动,实现"学生-商家"直接互动;
  2. 在线订餐功能:对接商家配送服务,学生可在平台下单、支付,形成"探索-分享-下单"闭环;
  3. 智能推荐功能:基于学生浏览历史、收藏偏好,通过简单算法推荐相似美食,提升个性化体验;
  4. 移动端适配:开发微信小程序版,学生无需登录网页,通过小程序即可使用核心功能,适配碎片化使用场景;
  5. 校园美食榜单:按月度/季度统计热门美食,生成"校园周边美食TOP10",增强平台活跃度。

如果本文对您的Spring Boot学习、校园服务类毕业设计有帮助,欢迎点赞 + 收藏 + 关注,后续会分享更多校园场景下的项目实战案例!