资讯动态

Spring Boot点餐系统毕业设计全解析:从数据库建模到部署答辩

发布时间:2026/10/20 10:41:53 来源:尧图企业网站定制
说实话每年到了毕业季找我帮忙看“点餐系统”代码的同学没有二十也有十五。这套基于Spring Boot的网上点餐管理系统在我接触过的毕业设计题目里属于出现频率最高的一档——它不涉及太复杂的算法却能把前端交互、后端接口、数据库建模、权限认证、订单状态流转这些核心知识点完整串起来非常适合用来展示一个学生的工程能力。很多同学拿到源码后第一反应是“代码能跑就行”但真到了答辩和写论文的时候才发现自己连模块之间的关系都讲不清楚。这篇文章我就以这套Spring Boot点餐系统为例子把整套设计思路、数据库建模、核心功能实现、部署调试的完整过程写出来顺便把我这些年帮人排查问题积攒下来的坑都列清楚。不管你是拿它当毕业设计还是想自己练手做一套完整项目都可以直接对着这篇文章一步步复现。1. 项目整体设计与技术选型解析1.1 为什么选Spring Boot作为基础框架先回答一个我在答疑时被问得最多的问题为什么几乎所有毕业设计都偏爱Spring Boot原因其实很实在。第一Spring Boot解决了传统SSM项目里最折磨人的配置问题。用过Spring MVC的同学都知道光一个web.xml、spring-mvc.xml、spring-mybatis.xml加一堆jar包依赖兼容性调整就能耗掉两三天。而Spring Boot用自动配置和起步依赖把这些全部收拢一个spring-boot-starter-web就能拉起一个可运行的Web应用这让新手能把精力集中在业务代码上而不是浪费在环境搭建上。第二内嵌Tomcat容器让部署变得极其轻量。传统项目需要单独装Tomcat、配置虚拟路径、手动丢war包Spring Boot直接java -jar就能启动这对后续远程调试和答辩演示都是巨大的便利。第三生态成熟社区资料丰富。无论是用户认证、支付对接还是文件上传Spring Boot都能找到成熟的整合方案。对于时间有限的毕业生来说这等于站在了巨人的肩膀上。回到点餐系统本身它的业务场景天然适合这个技术栈用户端要处理菜单浏览、加购、下单、支付商家端要管理菜品、订单状态管理后台要做数据统计和用户管理。这些功能拆解下来本质上就是一组RESTful接口加上数据库CRUD操作Spring Boot加MyBatis或者MyBatis-Plus的组合开发效率非常高。1.2 技术栈清单与版本选择的心得这套系统我推荐的技术栈如下版本号是我实测过可以稳定运行的组合组件推荐版本用途JDK1.8 / 11基础运行环境Spring Boot2.7.x后端主框架MyBatis-Plus3.5.xORM与分页MySQL5.7 / 8.0数据存储Redis可选5.x以上缓存与购物车Maven3.6依赖管理前端模板Thymeleaf / Vue ElementUI/微信小程序页面展示这里有一个重要的选型建议不要把版本追得太新。很多同学为了显得项目“前沿”一上来就选Spring Boot 3.x JDK 17结果发现MyBatis-Plus的旧版本不兼容或者网上大部分教程都是基于2.x写的遇到问题连资料都搜不到。我自己的习惯是毕业设计求稳不求新Spring Boot 2.7.x是最成熟稳定的选择相关问题和解决方案几乎都能搜到。关于前端有两种路线可选。一种是传统的服务端渲染用Thymeleaf直接把后台管理页面渲染出来另一种是前后端分离用Vue写前台点餐页面后端只提供JSON接口。如果你的论文需要展示“系统架构的先进性”建议选择前后端分离如果你更想把重心放在后端逻辑和答辩讲述上Thymeleaf方案能节省大量时间。我见过不少同学在Vue的脚手架和路由配置里卡了整整一周最后反而没时间打磨核心业务代码。2. 架构设计与功能模块拆解2.1 三类角色与模块职责划分一套完整的点餐系统至少需要支撑三类角色的使用场景普通用户、商家店主/管理员、平台运营者。设计初期把角色边界划清楚后续的表结构、接口权限、页面路由都会顺畅很多。普通用户端的功能主要围绕“点餐动作”展开注册登录、浏览菜品分类、查看菜品详情、加入购物车、提交订单、模拟支付、查看历史订单、管理收货地址和个人信息。这里面最核心的是购物车和下单流程我在第四部分会详细展开。商家端解决的是“店铺日常运营”问题菜品分类管理、菜品上下架、库存数量调整、订单接单/出餐/完成的状态推进、简单的销售统计。平台运营者端则是“全局视角”用户管理禁用/启用、商家审核、全平台订单查询、数据概览日订单量、销售额、热门菜品排行。模块划分上我习惯把项目拆成这几个子包结构答辩时也比较好讲com.example.ordering ├── common // 通用返回结果、异常处理、工具类 ├── config // 拦截器、跨域配置、MyBatis-Plus配置 ├── controller // 控制层接收请求 ├── service // 业务逻辑层接口 实现 ├── mapper // 数据访问层 ├── entity // 数据库实体类 ├── dto // 前端交互对象避免直接暴露实体 └── vo // 视图对象这个分层不是写代码的负担而是答辩时的加分项。面试官或者答辩老师看到你有意识地做controller、service、mapper的分层通常会认定你具备基本的工程素养。2.2 核心业务流程与状态机设计点餐系统最核心的业务链就是“浏览菜品 → 加入购物车 → 提交订单 → 支付 → 商家接单 → 出餐/配送 → 完成”。这条链路上最关键的是订单状态的设计。我在这套系统里把订单状态定义为以下枚举这个设计可以直接用到你的数据库字段注释和论文的状态图里状态值状态含义触发动作0待支付用户提交订单后1已支付/待接单用户完成支付后2已接单/制作中商家确认接单后3配送中/待取餐商家出餐后4已完成用户确认收货后5已取消用户取消或超时未付为什么要把订单状态拆这么细因为点餐是一个多人协作过程用户、商家、系统三方都需要通过状态感知“现在进行到哪一步”。如果你只设计“未完成/已完成”两个状态那商家无法知道自己该不该做菜用户也不知道自己的餐到哪一步了。状态机设计得当后续做页面状态展示、统计报表、超时自动取消都会非常轻松。还有一个容易被忽略的细节订单取消逻辑。我建议在待支付状态下允许用户主动取消同时加上一个定时任务比如超过15分钟未支付就自动关闭订单释放菜品库存。这个功能虽然小但写进论文的“系统亮点”里非常有用因为它涉及到了定时任务和并发库存回滚的问题。3. 数据库设计与核心表结构3.1 表结构总体规划与ER关系数据库是整套系统的地基。我的经验是先花半天时间把表设计好后面写代码的速度会翻倍。如果表设计得乱七八糟后面每写一个功能都是在给自己挖坑。这套点餐系统的核心表我建议这样划分用户表tb_user用户ID、用户名、密码、手机号、头像、昵称、创建时间、禁用标记地址表tb_address地址ID、用户ID、收货人姓名、电话、详细地址、默认标记菜品分类表tb_category分类ID、分类名称、排序号、状态菜品表tb_dish菜品ID、分类ID、菜品名称、图片、价格、描述、库存、销量、状态上架/下架购物车表tb_cart购物车ID、用户ID、菜品ID、数量、加入时间订单表tb_orders订单ID、订单号、用户ID、地址快照、总金额、状态、下单时间、支付时间订单明细表tb_order_detail明细ID、订单ID、菜品ID、菜品名称快照、单价快照、数量管理员表tb_admin管理员ID、账号、密码、角色超级管理员/商家、关联店铺ID这里有一个特别重要的经验订单表和订单明细表一定要拆分也就是“主表明细表”的设计模式。一个订单包含多个菜品如果把菜品信息直接塞进订单表后续统计“哪个菜卖得好”的时候就会非常痛苦。订单表存的是订单维度的信息谁买的、总价多少、什么状态订单明细表存的是菜品维度的信息买了哪些菜、每个菜多少钱。两张表通过订单ID关联查询的时候join一下即可。另外订单表和订单明细表里我特意强调了“快照”两个字。什么意思就是下单那一刻把菜品的名称和单价原样复制一份存进订单明细。为什么不能直接关联菜品表因为商家可能过几天就把菜品的价格改了或者把菜下架了如果订单明细是实时关联的你查历史订单的时候价格和菜名可能就变了。快照设计保证了历史订单的不可变性这个细节很多同学会忽略但写进论文非常加分。3.2 关键字段设计与容易踩的坑金额字段必须用decimal。这是我在代码评审里见到最多的错误。很多同学图省事把价格字段设计成double或者float结果前端显示出现0.1 0.2 0.30000000000000004这种诡异问题用户一看金额对不上直接投诉。所有涉及金额的字段一律用decimal(10, 2)在Java实体类里对应BigDecimal。这句建议值一万个赞记下来。用户密码必须加密存储。如果直接把明文密码存进数据库This is a huge риск风险。至少用MD5加盐处理更推荐用BCryptPasswordEncoder。答辩的时候老师很可能会问安全相关的问题你只要说“密码采用加盐哈希存储即使数据库泄露也不会暴露明文”这个回答就能让老师认可你的安全意识。订单号要独立生成且全局唯一。不要用数据库自增ID直接当订单号那样会暴露你的订单量也不利于后续对接支付、物流等外部系统。我常用的方案是时间戳 随机数或者用yyyyMMddHHmmss 用户ID 随机三位数拼一个订单号。保证唯一即可。下面给出三张核心表的建表SQL参考节选你可以直接改造使用CREATE TABLE tb_dish ( id BIGINT PRIMARY KEY AUTO_INCREMENT, category_id BIGINT NOT NULL COMMENT 所属分类, name VARCHAR(50) NOT NULL COMMENT 菜品名称, price DECIMAL(10,2) NOT NULL COMMENT 单价, image VARCHAR(255) DEFAULT NULL COMMENT 图片地址, stock INT DEFAULT 99 COMMENT 库存, sales INT DEFAULT 0 COMMENT 销量, status TINYINT DEFAULT 1 COMMENT 1上架 0下架, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); CREATE TABLE tb_orders ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL UNIQUE COMMENT 订单号, user_id BIGINT NOT NULL, total_amount DECIMAL(10,2) NOT NULL, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待支付 1已支付 2接单 3配送 4完成 5取消, receiver_name VARCHAR(30), receiver_phone VARCHAR(20), receiver_address VARCHAR(200), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, pay_time DATETIME DEFAULT NULL ); CREATE TABLE tb_order_detail ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_id BIGINT NOT NULL, dish_id BIGINT NOT NULL, dish_name VARCHAR(50) NOT NULL COMMENT 菜品快照, dish_price DECIMAL(10,2) NOT NULL COMMENT 价格快照, quantity INT NOT NULL );建表的时候还有两个实用习惯一是每张表都加上create_time和update_time字段用MySQL的DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP自动维护这样论文里写“系统记录了操作时间”才有依据二是给外键关联字段添加上索引否则订单量一上来联表查询会明显变慢。4. 核心功能实现与关键代码解读4.1 用户登录与登录态保持登录认证是整套系统的门面。没有登录态控制任何人都可以直接调接口下单或者管理菜品这显然是无法接受的。我这里推荐用JWTJSON Web Token来做登录态保持这也是目前行业内主流的方案。先说原理方便你答辩时讲清楚。用户登录成功后后端把用户ID、角色等信息签名生成一个token字符串返回给前端。前端后续每次请求都在Header里带上这个token。后端通过拦截器解析token从中取出用户身份放行请求或拒绝请求。因为token本身就是身份的凭证服务端不需要专门存一份登录状态天然支持前后端分离。核心代码如下基于jjwt库public class JwtUtils { private static final String SECRET your-secret-key-change-me; private static final long EXPIRE 7 * 24 * 60 * 60 * 1000L; // 7天 public static String generateToken(Long userId, String role) { return Jwts.builder() .claim(userId, userId) .claim(role, role) .setExpiration(new Date(System.currentTimeMillis() EXPIRE)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token) .getBody(); } }拦截器里这样处理public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token request.getHeader(Authorization); if (token null) { response.setStatus(401); return false; } try { Claims claims JwtUtils.parseToken(token.replace(Bearer , )); request.setAttribute(userId, claims.get(userId)); return true; } catch (Exception e) { response.setStatus(401); return false; } }然后把这个拦截器注册到WebMvc配置里指定哪些路径需要拦截registry.addInterceptor(new LoginInterceptor()) .addPathPatterns(/api/**) .excludePathPatterns(/api/user/login, /api/user/register, /api/dish/list, /api/dish/detail);这里有个容易踩的坑拦截器放行的路径一定要单独列清楚。很多同学写完全局拦截后发现自己前端页面连登录接口都调不通就是因为登录接口也被拦截了导致“死循环”——用户还没登录连登录请求都被401拒绝。4.2 购物车与下单流程的实现要点购物车是点餐系统的核心体验模块。我用的是基于Redis的购物车方案以用户ID作为key菜品ID作为field数量作为value用一个Hash结构搞定。这样不用为购物车单独建表存取速度也很快。Autowired private StringRedisTemplate redisTemplate; public void addToCart(Long userId, Long dishId, Integer quantity) { String key cart: userId; redisTemplate.opsForHash().increment(key, dishId.toString(), quantity); }如果不想引入Redis也可以用MySQL的购物车表实现逻辑上差别不大插入前先检查该用户是否已经加过同一菜品存在则更新数量不存在则新增记录。两者各有优劣Redis方案性能好且代码简洁MySQL方案则在论文里更容易画出表结构图。我个人的倾向是只要有条件用Redis因为答辩时“Redis实现购物车缓存”这个点本身就值得介绍。下单流程建议用Transactional事务包裹保证数据一致性Transactional(rollbackFor Exception.class) public OrderResult createOrder(Long userId, Long addressId) { // 1. 查询购物车内容 // 2. 校验菜品库存是否充足 // 3. 计算订单总金额用BigDecimal // 4. 插入订单表生成订单号状态为待支付 // 5. 批量插入订单明细表快照菜品名和价格 // 6. 扣减菜品库存 // 7. 清空购物车 }这里特别强调扣库存和创建订单必须处于同一个事务中。如果先创建订单成功、再扣库存失败会导致“订单有了但库存没减”等商家实际备菜的时候发现菜不够这就属于严重的数据一致性问题。加上Transactional之后任何一个环节抛出异常前面所有操作都会回滚数据库不会留下半截数据。4.3 支付模拟与订单状态推进毕业设计阶段一般不会真实对接支付因为申请支付商户号需要营业执照等资质学生通常不具备。所以这里我推荐做一个支付模拟用户点击“去支付”后前端弹出支付确认框后端直接把订单状态从“待支付”改成“已支付”。public PayResult pay(Long orderId, Long userId) { Order order orderMapper.selectById(orderId); if (order null || !order.getUserId().equals(userId)) { throw new BusinessException(订单不存在); } if (order.getStatus() ! 0) { throw new BusinessException(订单状态不是待支付状态); } order.setStatus(1); order.setPayTime(new Date()); orderMapper.updateById(order); return PayResult.success(order); }注意这里我做了两个关键校验一是订单归属校验二是状态校验。这两个校验在真实项目中至关重要防止用户“支付别人的订单”或者“重复支付一个已支付订单”。在论文的测试部分你至少要有意识地写出来“系统验证了越权访问被拦截”这个测试用例老师看到会很满意。订单状态推进我建议做一个统一的方法把状态变更的合法性收敛在一处而不是在各个service里直接setStatus。比如写一个OrderStateMachine类定义哪些状态可以转移到哪些状态不符合转移规则的直接抛异常。这样代码结构清晰后面维护状态逻辑只需要改这一个文件。5. 部署运行与远程调试实录5.1 本地环境搭建分步说明拿到源码或者自己写完之后第一步就是把项目跑起来。很多同学的噩梦从这里开始我直接把完整步骤写出来照着做基本不会出问题。第一步安装JDK 1.8并配置环境变量。安装完成后在命令行执行java -version看到java version 1.8.0_xxx就算成功。第二步安装Maven并配置阿里云镜像。打开Maven的settings.xml在mirrors节点里添加国内镜像这一步能解决90%的依赖下载慢和下载失败问题。mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror第三步安装MySQL。在Windows环境下用安装包版比解压版省心很多一路Next即可。安装完成后执行源码包里的init.sql脚本把初始数据导入数据库。注意看SQL文件里的建库语句如果里面有create database xxx就需要在MySQL里执行如果已经指定了数据库名后续要在配置文件里对应修改。第四步打开项目源码修改application.yml里的数据库连接信息。这里是最容易出错的地方spring: datasource: url: jdbc:mysql://localhost:3306/ordering_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver在MySQL连接串后面加上serverTimezoneAsia/Shanghai可以解决高版本MySQL驱动报时区错误的问题。加上characterEncodingutf8可以解决中文乱码问题。这两个参数几乎是新手最常踩的坑一定不要省。第五步在项目根目录执行mvn spring-boot:run或者在IDE里直接运行主类。启动成功后看到Started Application in xxx seconds和Tomcat启动端口的日志项目就运行起来了。5.2 启动报错排查速查表我整理了这套系统最常出现的报错和对应解法做成一个速查表建议截图保存报错信息原因解决方案Port 8080 was already in use8080端口被占用关闭占用进程或在yml里改server.portUnknown database ordering_db数据库没创建先执行SQL里的建库语句Access denied for user账号密码错误检查yml里的用户名密码Failed to configure a DataSource数据库连接配置缺失检查application.yml的datasource配置Cannot load driver class: com.mysql.cj.jdbc.Driver依赖缺失或版本不匹配检查pom.xml里mysql-connector-java依赖java.sql.SQLException: The server time zone value时区问题连接串加serverTimezoneAsia/Shanghaijava.lang.NoClassDefFoundError: org/springframework/...依赖冲突或未完整编译执行mvn clean后再mvn install页面中文显示乱码编码不一致保证IDE、数据库、连接串都为UTF-8还有一个“不是报错的报错”项目启动成功但访问页面一直白屏或者404。排查思路是先确认访问的端口是不是你项目启动日志里显示的那个再看Controller的RequestMapping路径和前端请求路径是否完全一致。很多时候是自己把CORS跨域配置漏了前后端分离的项目里前端访问后端接口会报跨域在config里加一个CorsFilter或者用CrossOrigin处理即可。5.3 远程安装调试的常见操作很多同学拿到的是“包远程安装调试”的资源这里我顺手讲讲远程协助过程中常见的操作流程。一般是通过远程桌面或远程控制工具连接到你电脑上由技术人员直接操作你的环境。你需要提前确认三件事电脑保持开机且网络通畅、把项目源码和数据库脚本放在容易找到的位置比如桌面、确认IDE已经安装好。如果远程调试过程中对方让你执行命令行操作你先调整好心态别急着打断。常见操作无非就是# 检查Java版本 java -version # 检查Maven构建 mvn clean package -DskipTests # 直接运行打包好的Jar java -jar target/ordering-system.jar这里有个有用的经验提前把target目录下打好的jar包保留好远程调试或者答辩的时候直接把java -jar运行起来比在IDE里点运行更“专业”。因为答辩现场很可能没有IDE或者IDE启动卡顿一个能独立运行的jar包才是真正的“成品”。6. 论文写作与答辩准备的实用建议6.1 论文结构怎么搭才不空洞拿到一套可运行的系统论文写起来其实很快。常见的问题是同学不知道该写多少字、写什么内容于是东拼西凑一些废话充字数。我建议按下面这个结构展开既完整又有说服力第一章绪论写研究背景和意义。这里不要空喊“随着互联网的发展”而是结合具体场景说传统纸质菜单点餐效率低、容易出错商家需要人工记录订单、统计销售通过一个在线点餐系统可以实现自助点餐、自动计费、订单数据可视化。第二章相关技术介绍。把Spring Boot、MyBatis-Plus、MySQL、Redis、JWT这些技术的基本概念写清楚每项控制在两三百字内重点是说明“为什么选用它”。第三章系统需求分析。这里建议画用例图和数据流图。至少列出用户用例浏览菜品、加购、下单、支付、查看订单、地址管理和商家用例菜品管理、订单管理。每类角色写清楚“能做什么”、有哪些前置条件。第四章系统设计。包括总体架构图、功能模块图、数据库ER图和核心表结构说明。我的经验是全章最好写了把代码里做好的模块划分和数据库表搬进去配上文字解释即可。第五章系统实现。按模块逐一说明配上核心代码和运行效果图。最具说服力的是把关键业务逻辑截图比如下单的事务方法、JWT拦截器、状态机的校验逻辑然后逐行解释。第六章系统测试。不要只写“测试通过”四个字。列出测试用例表格包括测试功能、操作步骤、预期结果、实际结果。我建议至少写10个用例覆盖正常流程和异常流程重复支付、超时取消、越权访问、库存不足等。6.2 答辩演示的操作建议答辩演示是很多人忽视但其实最关键的环节。我见过太多功能完整的系统因为演示时手忙脚乱而扣分。给你三个建议。第一准备一份独立的演示数据。提前注册好几个测试账号一个普通用户、一个商家管理员。菜品分类和菜品图片提前配好别等到演示现场才现录入。我强烈建议把菜品图片换成适合演示的高清图片视觉上会加分很多。第二把演示路径走顺。从用户注册登录开始依次演示浏览菜品、加入购物车、下单、支付、查看订单然后切换商家账号演示接单和出餐最后切到管理员账号演示用户管理和数据统计。一条清晰的业务闭环能展示你对整个系统的理解一定会给老师留下好印象。第三准备一个“亮点演示”。在答辩演示的最后刻意展示一个你做得最深入的功能细节。比如打开数据库查询订单表和明细表的快照数据或者清空缓存后让用户重新登录演示token失效或者把两个终端同时登录同一个账号提交同一个订单展示库存只能被扣减一次。这个亮点的杀伤力远超你介绍十页PPT。6.3 从“能跑”到“懂原理”的跨越我最担心的不是同学们拿不到好成绩而是拿着诚实的代码却讲不清楚。答辩老师通常会追问一些“代码背后”的问题“购物车为什么要存Redis”、“下单为什么加事务”、“JWT和Session有什么区别”。这些问题的答案其实不在代码注释里而在你的思考过程中。我的建议是写完一个功能就逼问自己三个问题——这个方案解决了什么问题如果不这么做会有什么后果还有没有其他方案把这三个问题的答案理解透答辩时你就能立于不败之地。另外很多人背下了别人代码里的注释却不知道报错如何处理。这其实是最危险的。答辩现场系统随时可能出问题与其死记硬背不如把启动流程、依赖关系、数据库字段含义都亲手敲一遍、理解一遍。把源码里的application.yml、pom.xml、核心SQL语句打开逐行看明白每个配置的含义。相信我这个工程量的价值远大于背十篇论文摘要。我个人在实际操作中的体会是这套点餐系统之所以能成为经典毕业设计题目不是因为它技术多复杂而是因为它把一个完整的业务闭环讲清楚了。用户从点餐到吃完商家从接单到出餐每一个环节都有对应的数据流转和状态变化。只要你能把这个闭环吃透代码是谁写的其实已经不重要了。后续如果你想进阶可以在这个基础上加上图表统计的前端可视化、微信小程序端、或者简单的推荐算法这些扩展方向在找工作的时候也都能当作品集方向。最后再分享一个小技巧把你自己在开发过程中真实遇到的报错和解决方案记录下来无论是一页笔记还是在社交平台上发一条动态都行。这套“问题日志”既是论文测试章节的素材也是答辩时回答“你遇到过什么难点”这个问题的最好底稿。好项目不是一次写出来的是改出来的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑