目录
项目简介
功能设计
数据库表设计
用户表
订单表
菜品表
订单详情表(关联菜品表和订单表)
配置类
实体类
Dish
OrderDetail
OrderInfo
UserInfo
统一后端返回内容
用户模块
用户注册功能
mapper接口
xml文件
controller层
前端
用户登录功能
验证用户账号和密码(session存储)
session key值
controller层
mapper层
xml
前端
显示所有用户可以点的菜品列表
显示菜品
controller层
mapper层
xml
前端
统计点的菜品个数以及下单总价
刷新页面维持用户登录状态功能
退出登录功能
前端
controller
用户下单菜品功能
controller层
mapper层
xml
用户查看订单详情功能
前端
controller
mapper接口
xml
商家模块
商家登录功能
前端
controller
mapper
xml
保持登录状态
前端
controller
菜品添加功能
前端
controller
mapper
xml
菜品删除功能
前端
controller
mapper
xml
获取订单列表功能
前端
查看所有订单
修改订单状态
查看某个订单详情
controller
查看所有订单
修改订单状态
查看某个订单详情
mapper
查看所有订单
修改订单状态
查看某个订单详情
xml
查看所有订单
修改订单状态
查看某个订单详情
退出登录功能
前端
controller
项目简介
现如今,随着餐饮行业的不断扩大,消费者的年轻化,餐饮行业的点餐逐渐由线下转为线上点单,因此我们这个点餐系统就应运而生。点餐系统为餐厅增添了用户与餐厅的互动性,还可以实现更加多样化的点餐。
本项目运用spingboot + springmvc + mybatis + vue实现了一个具有商家和普通用户的双角色点餐系统。
功能设计
数据库表设计
用户表
- 主键id(自增)
- 用户名
- 密码
- 身份标识
+----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | username | varchar(250) | YES | | NULL | | | password | varchar(50) | YES | | NULL | | | isadmin | int(11) | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+
订单表
- 订单主键ID(自增)
- 用户ID
- 订单创建时间
- 状态(0:未完成; 1:已完成)
+------------+----------+------+-----+-------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+----------+------+-----+-------------------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | uid | int(11) | YES | | NULL | | | createtime | datetime | YES | | CURRENT_TIMESTAMP | | | status | int(11) | YES | | NULL | | +------------+----------+------+-----+-------------------+----------------+
菜品表
- 主键ID(自增)
- 菜品名
- 价格
+-------+---------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+---------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(250) | NO | | NULL | | | price | decimal(10,0) | NO | | NULL | | +-------+---------------+------+-----+---------+----------------+
订单详情表(关联菜品表和订单表)
- 订单id
- 菜品id
+-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | did | int(11) | NO | | NULL | | | oid | int(11) | NO | | NULL | | +-------+---------+------+-----+---------+-------+
这个表是为了处理订单表和菜品表的多对多关系,也就是中间表
配置类
package com.example.ordersys.config; /** * @author SongBiao * @Date 2021/1/18 */ //此类专门存储session中的key值 public class AppFinal { //将session中的key值提取出来,单独放到一个类里面去 //用户的session key public static final String USERINFO_SESSION_KEY = "USERINFO_SESSION_KEY"; }
此类用于统一session存储过程中的key值
实体类
Dish
package com.example.ordersys.model; import lombok.Data; import java.math.BigDecimal; /** * @author SongBiao * @Date 2021/1/18 */ @Data public class Dish { private int id; private String name; private BigDecimal price; }
OrderDetail
package com.example.ordersys.model; import lombok.Data; /** * @author SongBiao * @Date 2021/1/18 */ @Data public class OrderDetail { private int oid; private int did; private Dish dish; }
OrderInfo
package com.example.ordersys.model; import lombok.Data; import java.util.Date; /** * @author SongBiao * @Date 2021/1/18 */ @Data public class OrderInfo { private int id; private int uid; private Date createtime; private int status; private String uname; }
UserInfo
package com.example.ordersys.model; import lombok.Data; /** * @author SongBiao * @Date 2021/1/18 */ @Data public class UserInfo { private int id; private String username; private String password; private int isadmin; }
统一后端返回内容
package com.example.ordersys.tools; import lombok.Data; /** * @author SongBiao * 此类用于规范controller类返回的数据类型的统一,我们定义如下类 * @Date 2021/1/18 */ @Data public class ResponseBody<T> { //后端返回给前端的状态 private int status; //定义参数的描述信息 private String msg; //后端返回给前端的数据 private T data; public ResponseBody(int status, String msg, T data){ this.status = status; this.msg = msg; this.data = data; } }
用户模块
用户注册功能
mapper接口
//注册方法 public int register(UserInfo userInfo);
xml文件
<insert id="register"> insert into userinfo(username,password,isadmin) values(#{username},#{password},0) </insert>
controller层
/** * 用户注册功能,这里指的是顾客 */ @RequestMapping("/reg") public ResponseBody<Integer> register(UserInfo userInfo) { int data = userMapper.register(userInfo); return new ResponseBody<>(0, "", data); }
前端
<!-- 注册窗口 --> <v-row justify="center"> <v-dialog v-model="reg.showRegister" persistent max-width="400px"> <v-card> <v-card-title> <span class="headline">注册</span> </v-card-title> <v-card-text> <v-container> <v-row> <v-col cols="12" sm="12"> <v-text-field label="用户名*" v-model="reg.name" required></v-text-field> </v-col> </v-row> <v-row> <v-col cols="12" sm="12"> <v-text-field label="密码*" v-model="reg.password" required></v-text-field> </v-col> </v-row> <v-row> <v-col cols="12" sm="12"> <v-text-field label="确认密码*" v-model="reg.password2" required></v-text-field> </v-col> </v-row> <v-row> <v-col cols="12" sm="6"> <v-btn color="primary" block v-on:click="doRegister">注册</v-btn> </v-col> <v-col cols="12" sm="6"> <v-btn color="primary" block v-on:click="reg.showRegister = false">取消 </v-btn> </v-col> </v-row> </v-container> </v-card-text> </v-card> </v-dialog> </v-row>
// 注册方法 doRegister() { //获取用户输入的值,通过v-model来确定如何获取值 let username = app.reg.name; let password = app.reg.password; let password2 = app.reg.password2; //非空校验 if (username == "") { alert("请先输入用户名"); return false; } if (password == "") { alert("请先输入密码"); return false; } if (password2 == "") { alert("请先输入确认密码"); return false; } if (password != password2) { alert("两次输入的密码不一致,请核对"); return false; } //请求后端接口实现注册功能 jQuery.getJSON("/user/reg", { "username": username, "password": password }, function (result) { if (result != null && result.data != null && result.data > 0) { alert("恭喜添加成功"); //每次一个用户注册信息后将信息置空 app.reg.name = ""; app.reg.password = ""; app.reg.password2 = ""; //隐藏注册窗体 app.reg.showRegister = false; } else { alert("抱歉,添加失败,请重试"); } }); },
用户登录功能
(1)验证用户的账号和密码
(2)存储session信息
(3)显示欢迎信息
(4)显示所有用户可以点的菜品列表
(5)刷新页面维持页面登录状态
(6)退出登录
验证用户账号和密码(session存储)
session key值
package com.example.ordersys.config; /** * @author SongBiao * @Date 2021/1/18 */ //此类专门存储session中的key值 public class AppFinal { //将session中的key值提取出来,单独放到一个类里面去 //用户的session key public static final String USERINFO_SESSION_KEY = "USERINFO_SESSION_KEY"; }
controller层
//登录功能 @RequestMapping("/login") public ResponseBody<UserInfo> login(UserInfo userInfo, HttpServletRequest request) { UserInfo user = userMapper.login(userInfo); //登录后将信息存入session当中 if (user != null && user.getId() > 0) { HttpSession session = request.getSession(); session.setAttribute(AppFinal.USERINFO_SESSION_KEY, user); } return new ResponseBody<>(0, "", user); }
mapper层
//登录方法 public UserInfo login(UserInfo userInfo);
xml
<select id="login" resultType="com.example.ordersys.model.UserInfo"> select * from userinfo where username=#{username} and password=#{password} </select>
前端
// 登录方法 doLogin() { //获取用户输入的用户名和密码,还是看v-model let username = app.login.inputUsername; let password = app.login.inputPassword; //非空校验 if (username == "") { alert("请输入用户名"); return false; } if (password == "") { alert("请输入密码"); return false; } //访问后端接口,验证用户信息 jQuery.getJSON("/user/login", { "username": username, "password": password }, function (result) { if (result != null && result.data != null && result.data.id > 0) { //登录成功 alert("登录成功!"); //登录成功后,隐藏左侧未登录之前的导航,并显示欢迎信息 //因为两者的v-show是一样的 app.login.isLogin = true; //去掉登录时的窗口,还是查看v-model app.login.showLoginDialog = false; //请求后端得到菜品列表 jQuery.getJSON("/dish/list", {}, function (result) { if (result != null && result.data != null) { app.dishes = result.data; } }); } else { //用户名或密码错误,请重新输入 alert("用户名或密码错误,请重新输入"); } }); },
显示所有用户可以点的菜品列表
显示菜品
controller层
@RequestMapping("/list") public ResponseBody<List<Dish>> getList() { List<Dish> data = dishMapper.getDishList(); return new ResponseBody<>(0, "", data); }
mapper层
//查询菜单列表 public List<Dish> getDishList();
xml
<select id="getDishList" resultType="com.example.ordersys.model.Dish"> select * from dish </select>
前端
<v-simple-table v-show="status == 'dishesPage' && login.isLogin"> <template v-slot:default> <thead> <tr> <th class="text-left">菜名</th> <th class="text-left">价格</th> <th class="text-left">选择</th> </tr> </thead> <tbody> <tr v-for="dish in dishes"> <td> <v-icon>mdi-food</v-icon> {{dish.name}} </td> <td> <v-icon>mdi-cash</v-icon> {{dish.price}} </td> <!-- 选择窗体--> <td> <v-switch v-model="dish.isSelected"></v-switch> </td> </tr> </tbody> </template> </v-simple-table>
jQuery.getJSON("/dish/list", {}, function (result) { if (result != null && result.data != null) { app.dishes = result.data; } });
统计点的菜品个数以及下单总价
<v-row v-show="status == 'dishesPage' && login.isLogin"> <v-col :col="11"> <div class="pa-2">已点 {{selectedDishCount}} 道菜, 总计 {{selectedDishPrice}} 元</div> </v-col> </v-row>
computed: { // 点餐的个数 selectedDishCount() { let count = 0; this.dishes.forEach(dish => { if (dish.isSelected) { count++; } }); return count; }, // 计算下单的菜品总价 selectedDishPrice() { let price = 0; this.dishes.forEach(dish => { if (dish.isSelected) { price += dish.price; } }) return price; } },