点餐项目实现(一)

简介: 点餐项目实现(一)

目录

项目简介

功能设计

数据库表设计

用户表

订单表

菜品表

订单详情表(关联菜品表和订单表)

配置类

实体类

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实现了一个具有商家和普通用户的双角色点餐系统。

功能设计

image.png

数据库表设计

用户表

  • 主键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)显示欢迎信息

image.png

(4)显示所有用户可以点的菜品列表

image.png

(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;
    }
},


相关文章
|
存储 分布式计算 数据可视化
大数据常用技术与工具
【10月更文挑战第16天】
748 4
|
域名解析 缓存 网络协议
如何解决域名解析不生效问题?
文中对域名解析不生效的原因进行了分析,并针对最常见的本地递归域名服务器缓存不生效的问题提出了解决方案,尤其移动域名解析HTTPDNS对无线场景下的应用特别有效。
32693 0
|
消息中间件 监控 Java
使用Java进行实时数据处理的工具和技术
使用Java进行实时数据处理的工具和技术
|
机器学习/深度学习 人工智能 算法
从零构建现代深度学习框架(TinyDL-0.01)
本文主要以一个Java工程师视角,阐述如何从零(无任何二三方依赖)构建一个极简(麻雀虽小五脏俱全)现代深度学习框架(类比AI的操作系统)。
|
人工智能 城市大脑 运维
阿里云官网政企业务频道上线!
阿里云官网政企业务频道上线!
427 0
搭建esp32-idf开发环境并烧入第一个程序
搭建esp32-idf开发环境并烧入第一个程序
842 0
|
关系型数据库 MySQL 索引
[Lnmpa] Mysql 内存分配&参数配置&优化方案详解
背景介绍Lnmpa、Lamp、Lnmp等环境的教程很多,但是在默认安装后,很容易出现内存占用光,出现OOM等问题,为了更好的让服务器稳定运行,需要对每个应用服务进行内存配置方面的优化。
6925 0
|
算法
基于matlab实现生成模糊fis文件,包括模糊隶属函数和模糊规则等,不使用fuzzy工具箱
基于matlab实现生成模糊fis文件,包括模糊隶属函数和模糊规则等,不使用fuzzy工具箱
668 0
|
存储 消息中间件 缓存
基于 MaxCompute 的实时数据处理实践
MaxCompute 通过流式数据高性能写入和秒级别查询能力(查询加速),提供EB级云原生数仓近实时分析能力;高效的实现对变化中的数据进行快速分析及决策辅助。当前Demo基于近实时交互式BI分析/决策辅助场景,实现指标卡近实时BI分析、近实时市场监测、近实时趋势分析、近实时销量拆分功能。
2134 1
基于 MaxCompute 的实时数据处理实践