点餐项目实现

news2024/11/29 8:54:04

目录

  • 项目简介
  • 功能设计
  • 数据库表设计
    • 用户表
    • 订单表
    • 菜品表
    • 订单详情表(关联菜品表和订单表)
  • 配置类
  • 实体类
    • 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;
    }
},

刷新页面维持用户登录状态功能

//判断是否登录的方法
isLogin() {
    jQuery.getJSON("/user/islogin", {}, function (result) {
        if (result != null && result.data != null && result.data.id > 0) {
            //此时确定为登录状态,点击刷新后应该仍在主页面,而不是需要重新登录
            app.login.isLogin = true;
            //设置欢迎信息
            app.login.inputUsername = result.data.username;
            //请求后端得到菜品列表
            jQuery.getJSON("/dish/list", {}, function (result) {
                if (result != null && result.data != null) {
                    app.dishes = result.data;
                }
            });
        }
    });
},

注意要在最后调用这个isLogin方法
在这里插入图片描述

controller层

/**
 * 判断登录状态
 *
 * @param request
 * @return
 */
@RequestMapping("/islogin")
public ResponseBody<UserInfo> isLogin(HttpServletRequest request) {
    UserInfo user = null;
    HttpSession session = request.getSession(false);
    if (session != null && session.getAttribute(AppFinal.USERINFO_SESSION_KEY) != null) {
        user = (UserInfo) session.getAttribute(AppFinal.USERINFO_SESSION_KEY);
    }
    return new ResponseBody<UserInfo>(0, "", user);
}

isLogin方法是判断当前登录后,刷新页面不退出登录状态,最后在app外面调用了这个isLogin方法
原理是每次vue刷新页面会把就是会把变量如果改变了再全部变为初始值,所以如果我们不去设置isLogin方法的话,最终当我门点击刷新后,isLogin这个属性重新置为false,那么就会显示我们的导航栏了:因为!login.isLogin为true,
在这里插入图片描述

退出登录功能

前端

<v-list-item link v-on:click="logout">
    <v-list-item-action>
        <v-icon>mdi-logout</v-icon>
    </v-list-item-action>
    <v-list-item-content>
        <v-list-item-title>退出登录</v-list-item-title>
    </v-list-item-content>
</v-list-item>
//退出登录功能
logout() {
    if (confirm("是否确认退出?")) {
        jQuery.getJSON("/user/logout", {}, function (result) {
            if (result != null && result.data != null && result.data > 0) {
                //退出成功
                alert("退出成功");
                //刷新当前页面
                location.href = location.href;
            } else {
                alert("抱歉,操作失败,请重试");
            }
        });
    }
},

controller

/**
 * 退出登录
 * @param request
 * @return
 */
@RequestMapping("/logout")
public ResponseBody<Integer> logOut(HttpServletRequest request) {
    int data = 0;
    HttpSession session = request.getSession(false);
    if (session != null && session.getAttribute(AppFinal.USERINFO_SESSION_KEY) != null) {
        session.removeAttribute(AppFinal.USERINFO_SESSION_KEY);
        data = 1;
    }
    session.removeAttribute(AppFinal.USERINFO_SESSION_KEY);
    return new ResponseBody<>(0, "", data);

}

用户下单菜品功能

<v-col :cols="2">
    <v-btn color="primary" block v-on:click="dishSubmit">下单</v-btn>
</v-col>
dishSubmit() {
    if (confirm("确实提交?")) {
        let dids = "";//菜品id集合
        app.dishes.forEach(dish => {
            //选中了菜品就加1
            if (dish.isSelected) {
                dids += (dish.id + ",");
            }
        });
        if (dids != null) {
            //dids不等于null说明菜品已经下单提交,请求后端实现点餐
            //传递的参数为菜品id的集合
            jQuery.getJSON("/order/add", {"dids": dids}, function (result) {
                if (result != null && result.data != null && result.data > 0) {
                    alert("恭喜:点餐成功");
                }
            });
        } else {
            alert("请先选中菜品信息");
        }
    }
},

controller层

(1)菜品信息插入到OrderInfo表中

首先拿到下单的用户uid,从而拿到对应的订单oid

(2)中间表OrderDetail也要完成订单与菜品的关联

将之前拿到的订单oid与前端传来的菜品dids进行关联

@RequestMapping("/add")
public ResponseBody<Integer> addOrder(String dids, HttpServletRequest request) {
    int data = 0;
    //1:添加订单信息,返回一个订单ID
    //(1):要想添加订单信息,第一步是获取用户的id,因为在订单列表中,用户id是订单表的逻辑外键
    //我们是要通过用户的id来拿到对应的订单id

    // 如果当前Session没有就为null
    HttpSession session = request.getSession(false);
    if (session != null && session.getAttribute(AppFinal.USERINFO_SESSION_KEY) != null) {
        int uid = ((UserInfo) session.getAttribute(AppFinal.USERINFO_SESSION_KEY)).getId();
        //(2):将用户的id存入到OrderInfo
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setUid(uid);
        //订单添加方法
        //result代表添加影响的行数
        //addOrder方法会获取到订单表的自增id
        int result = orderInfoMapper.addOrder(orderInfo);

        //result大于0说明插入成功,因为在使用MyBatis做持久层时,insert语句默认是不返回记录的主键值,而是返回插入的记录条数
        if (result > 0) {
            //2:添加订单详情,需要用到订单ID
            data = orderDetailMapper.add(orderInfo.getId(), dids.split(","));
        }

    }
    return new ResponseBody<>(0, "", data);
}

mapper层

//添加订单
public int addOrder(OrderInfo orderInfo);
//传参的时候订单的id可能只有一个,但是菜品的id可能有多个,所以用String数组来表示
public int add(int oid,String[] dids);

xml

<!--注意此处插入时需要获取自增id,则需要使用useGeneratedKeys和keyProperty
keyProperty会将得到的主键id值赋给对应表中的主键,useGeneratedKeys为是否使用自动主键,肯定值为true-->
<insert id="addOrder" useGeneratedKeys="true" keyProperty="id">
 insert into orderinfo(uid,status) values(#{uid},0)
</insert>

注意:在使用MyBatis做持久层时,insert语句默认是不返回记录的主键值,而是返回插入的记录条数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TfIWhawh-1669814415971)(点餐项目.assets/image-20221129170348928.png)]

<!--使用foreach来遍历我们前台传过来的菜单id这个集合,将集合中的每一条数据存入到did中
oid代表订单id,订单id只有一个,但是菜单id可以有很多个,因为每个菜品都对应一个id -->
<!--因为我们要往did中插入的菜单id是一个集合,所以我们可以使用foreach循环,collection是
集合,我们放入的是add方法的参数:数组dids,item代表列,separator代表分隔符,意思就是
values后面是(),(),()这样的形式-->
<insert id="add">
    insert into orderdetail(oid,did) values
    <foreach collection="dids" item="item" separator=",">
        (#{oid},#{item})
    </foreach>
</insert>

用户查看订单详情功能

前端

显示用户自身订单状态代码

<v-list-item link v-on:click="orderList">
    <v-list-item-action>
        <v-icon>mdi-cart-outline</v-icon>
    </v-list-item-action>
    <v-list-item-content>
        <v-list-item-title>我的订单</v-list-item-title>
    </v-list-item-content>
</v-list-item>
orderList() {
    jQuery.getJSON("/order/list", {}, function (result) {
        if (result != null && result.data != null) {
            //获取订单列表成功
            app.orders = result.data;
            app.status = 'ordersPage';
        } else {
            //获取订单失败
            alert("获取订单列表失败,请重试");
        }

    });
},
<!-- 个人订单列表 -->
<v-simple-table v-show="status == 'ordersPage' && login.isLogin">
    <template v-slot:default>
        <thead>
        <tr>
            <th class="text-left">序号</th>
            <th class="text-left">状态</th>
            <th class="text-left">时间</th>
            <th class="text-left">详情</th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="order in orders">
            <td>{{order.id}}</td>
            <!--三元运算符在vue中可以使用-->
            <td>{{order.status==0?'未完成':'已完成'}}</td>
            <td>{{order.createtime}}</td>
            <td>
                <v-btn color='primary' v-on:click="detail(order.id)">查看详情</v-btn>
            </td>
        </tr>
        </tbody>
    </template>
</v-simple-table>

查看详情的代码

<!-- 某个订单的详情 -->
<v-row justify="center">
    <v-dialog v-model="showCurOrder" persistent max-width="600px">
        <v-simple-table>
            <template v-slot:default>
                <thead>
                <tr>
                    <th class="text-left">菜品</th>
                    <th class="text-left">价格</th>
                </tr>
                </thead>
                <tbody>
                <tr v-for="dish in curOrder">
                    <td>{{dish.dish.name}}</td>
                    <td>{{dish.dish.price}}</td>
                </tr>
                <tr>
                    <td>总金额:{{curOrderMoney()}}</td>
                    <td>
                        <v-btn color="primary" v-on:click="showCurOrder = false">关闭</v-btn>
                    </td>
                </tr>
                </tbody>
            </template>
        </v-simple-table>
    </v-dialog>
</v-row>
//计算某个订单详情的总钱数
curOrderMoney() {
    let money = 0;
    app.curOrder.forEach(order => {
        money += order.dish.price;
    });
    return money;
},
//查看订单详情
detail(oid) {
    jQuery.getJSON("/detail/list", {"oid": oid}, function (result) {
        if (result != null && result.data != null) {
            app.curOrder = result.data;
            //显示订单详情页面
            app.showCurOrder = true;
        }
    });
},

controller

显示订单代码

/**
 * 用户获取订单列表
 *
 * @return
 */
@RequestMapping("/list")
public ResponseBody<List<OrderInfo>> getList(HttpServletRequest request) {
    List<OrderInfo> orderinfo = null;
    HttpSession session = request.getSession(false);
    int uid = 0;
    if (session != null && session.getAttribute(AppFinal.USERINFO_SESSION_KEY) != null) {
        //获取用户id
        uid = ((UserInfo) session.getAttribute(AppFinal.USERINFO_SESSION_KEY)).getId();
        orderinfo = orderInfoMapper.list(uid);
    }
    return new ResponseBody<>(0, "", orderinfo);
}

查看详情代码

@RequestMapping("/list")
public ResponseBody<List<OrderDetail>> getList(int oid){
    List<OrderDetail> list = orderDetailMapper.getList(oid);
    return new ResponseBody<>(0,"",list);
}

mapper接口

显示订单代码

//获取订单列表
public List<OrderInfo> list(int uid);

查看详情代码

public List<OrderDetail> getList(int oid);

xml

显示订单代码

<select id="list" resultType="com.example.ordersys.model.OrderInfo">
   select * from orderinfo where uid=#{uid}
</select>

查看详情代码

这里要注意,先来看订单详情表的实体类设计:

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

可以看到OrderDetail实体类中还有一个Dish对象,但是注意这个对象在我们表中是没有的,原因是当我们用户查看订单详情的时候,需要查看菜品的详细信息以及总价格,我们直接再这里定义一个对象后,后期通过连表查询,然后将查询的结果包装成一个Dish类对象即可。那么我们再xml中就需要使用resultMap来指定对应的映射关系

首先再DishMapper.xml中指定dish表对应的实体类的映射关系;

<resultMap id="BaseResultMap" type="com.example.ordersys.model.Dish">
    <id column="id" property="id"></id>
    <result column="name" property="name"></result>
    <result column="price" property="price"></result>
</resultMap>

同时再OrderDetailMapper.xml中指定OrderDetail实体类的映射关系,注意需要使用到association属性来表示一对一的关系,因为后期我们使用连表查询中,orderdetail与dish进行左连接后,查询出来的记录是一行一行的,也就是说一个订单编号对应一个菜品名称,而不是多个

<resultMap id="BaseResultMap" type="com.example.ordersys.model.OrderDetail">
        <result property="did" column="did"></result>
        <result property="oid" column="oid"></result>
        <association property="dish" columnPrefix="d_" resultMap="com.example.ordersys.mapper.DishMapper.BaseResultMap">
        </association>
    </resultMap>
    
    
    
<select id="getList" resultMap="BaseResultMap">
    select o.*,d.name d_name,d.price d_price from orderdetail o left join dish d on o.did=d.id
   where o.oid=#{oid}
</select>
mysql> select o.*,d.name d_name,d.price d_price from orderdetail o left join dish d on o.did=d.id
    ->    where o.oid=16;
+-----+-----+--------+---------+
| did | oid | d_name | d_price |
+-----+-----+--------+---------+
|   3 |  16 | 红烧肉 |      30 |
|   4 |  16 | 茄子   |      25 |

这里就可以显示出订单编号为16的用户点了两个菜,其菜品编号为3,4,菜品名称为红烧肉,茄子,价格分别为30,25

注意这里我们使用了连表查询(左连接)

商家模块

商家登录功能

前端

<!-- 左侧导航 -->
<v-navigation-drawer v-model="drawer" app>
    <v-list dense v-show="!login.isLogin">
        <v-list-item link v-on:click="login.showLoginDialog=true">
            <v-list-item-action>
                <v-icon>mdi-login</v-icon>
            </v-list-item-action>
            <v-list-item-content>
                <v-list-item-title>登录</v-list-item-title>
            </v-list-item-content>
        </v-list-item>
    </v-list>
<v-row justify="center">
    <v-dialog v-model="login.showLoginDialog" 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="login.inputUsername" required>
                            </v-text-field>
                        </v-col>
                    </v-row>
                    <v-row>
                        <v-col cols="12" sm="12">
                            <v-text-field label="密码*" v-model="login.inputPassword" required>
                            </v-text-field>
                        </v-col>
                    </v-row>
                    <v-row>
                        <v-col cols="12" sm="6">
                            <v-btn color="primary" block v-on:click="userLogin">登录</v-btn>
                        </v-col>
                        <v-col cols="12" sm="6">
                            <v-btn color="primary" block v-on:click="login.showLoginDialog=false">取消
                            </v-btn>
                        </v-col>
                    </v-row>
                </v-container>
            </v-card-text>
        </v-card>
    </v-dialog>
</v-row>
userLogin() {
    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) {
            //等于1,说明是管理员登录
            if (result.data.isadmin == 1) {
                //登录成功
                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("非法操作,权限不足");
            }
        } else {
            //用户名或密码错误,请重新输入
            alert("用户名或密码错误,请重新输入");
        }
    });
},

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);
}
@RequestMapping("/list")
public ResponseBody<List<Dish>> getList() {
    List<Dish> data = dishMapper.getDishList();
    return new ResponseBody<>(0, "", data);
}

mapper

//登录方法
public UserInfo login(UserInfo userInfo);
//查询菜单列表
public List<Dish> getDishList();

xml

<select id="getDishList" resultType="com.example.ordersys.model.Dish">
   select * from dish
</select>
<select id="login" resultType="com.example.ordersys.model.UserInfo">
    select * from userinfo where
    username=#{username} and password=#{password}
</select>

保持登录状态

前端

//保持登录状态的方法
isLogin() {
    jQuery.getJSON("/user/islogin", {}, function (result) {
        if (result != null && result.data != null && result.data.id > 0) {
            if (result.data.isadmin == 1) {
                //等于1是超级管理员
                //此时确定为登录状态,点击刷新后应该仍在主页面,而不是需要重新登录
                app.login.isLogin = true;
                //设置欢迎信息
                app.login.inputUsername = result.data.username;
                //请求后端得到菜品列表
                jQuery.getJSON("/dish/list", {}, function (result) {
                    if (result != null && result.data != null) {
                        app.dishes = result.data;
                    }
                });
            }
        }
    });
},

在new Vue外部调用isLogin方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kgL3SaIs-1669814415972)(点餐项目.assets/image-20221130114507392.png)]

controller

@RequestMapping("/islogin")
public ResponseBody<UserInfo> isLogin(HttpServletRequest request) {
    UserInfo user = null;
    HttpSession session = request.getSession(false);
    if (session != null && session.getAttribute(AppFinal.USERINFO_SESSION_KEY) != null) {
        user = (UserInfo) session.getAttribute(AppFinal.USERINFO_SESSION_KEY);
    }
    return new ResponseBody<UserInfo>(0, "", user);
}

菜品添加功能

前端

<v-row v-show="status == 'dishesPage' && login.isLogin">
    <v-col :col="11">
    </v-col>
    <v-col :cols="2">
        <v-btn color="primary" block v-on:click="showAddDish = true">新增菜品</v-btn>
    </v-col>
</v-row>
<!-- 新增菜品 -->
<v-row justify="center">
    <v-dialog v-model="showAddDish" persistent max-width="600px">
        <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="newDish.name" required></v-text-field>
                        </v-col>
                    </v-row>
                    <v-row>
                        <v-col cols="12" sm="12">
                            <v-text-field label="价格(元)*" v-model="newDish.price" required>
                            </v-text-field>
                        </v-col>
                    </v-row>
                    <v-row>
                        <v-col cols="12" sm="6">
                            <v-btn color="primary" block v-on:click="addDish()">新增</v-btn>
                        </v-col>
                        <v-col cols="12" sm="6">
                            <v-btn color="primary" block v-on:click="showAddDish = false">取消</v-btn>
                        </v-col>
                    </v-row>
                </v-container>
            </v-card-text>
        </v-card>
    </v-dialog>
</v-row>
//新增菜品
addDish() {
    if (confirm("确认是否提交?")) {
        let name = app.newDish.name;
        let price = app.newDish.price;
        //
        if (name == "") {
            alert("请先输入菜品名称!");
            return false;
        }
        if (price == "" || price == 0) {
            alert("请先输入价格!");
            return false;
        }
        jQuery.getJSON("/dish/add", {"name": name, "price": price},
            function (result) {
                if (result != null && result.data != null && result.data > 0) {
                    //data>0表示添加成功
                    alert("恭喜:菜品添加成功!");
                    //每次添加完菜品后自动刷新
                    location.href = location.href;
                } else {
                    alert("抱歉:操作失败请重试!");
                }
            });
    }
},

controller

//管理员添加菜品的后台方法
@RequestMapping("/add")
public ResponseBody<Integer> addDish(Dish dish) {
    int data = dishMapper.addDish(dish);
    return new ResponseBody<>(0, "", data);
}

mapper

public int addDish(Dish dish);

xml

<insert id="addDish">
    insert into dish(name,price)
     values(#{name},#{price})
</insert>

菜品添加的逻辑就是每次添加完菜品到Dish表后,刷新页面,调用isLogin方法判断是否延续登录状态,然后isLogin方法重新获取后台的菜单列表,然后进行展示

菜品删除功能

前端

<td>
    <v-btn color="primary" v-on:click="del(dish.id)">删除</v-btn>
</td>
//删除菜品
del(did) {
    if (confirm("确认删除?")) {
        jQuery.getJSON("/dish/del", {"id": did}, function (result) {
            if (result != null && result.data != null && result.data > 0) {
                //删除成功
                alert("删除成功");
                //刷新当前界面
                location.href = location.href;
            } else {
                alert("抱歉,操作失败,请重试");
            }
        });
    }
},

controller

//管理员删除订单的后台方法
@RequestMapping("/del")
public ResponseBody<Integer> deleteDish(int id) {
    int data = dishMapper.del(id);
    return new ResponseBody<>(0, "", data);
}

mapper

public int del(int id);

xml

<delete id="del">
    delete from dish where id=#{id}
</delete>

菜品删除的逻辑就是每次删除菜品后,刷新页面,调用isLogin方法判断是否延续登录状态,然后isLogin方法重新获取后台的菜单列表,然后进行展示

获取订单列表功能

前端

查看所有订单

 <v-list-item link v-on:click="showOrder">
                <v-list-item-action>
                    <v-icon>mdi-cart-outline</v-icon>
                </v-list-item-action>
                <v-list-item-content>
                    <v-list-item-title>查看订单</v-list-item-title>
                </v-list-item-content>
            </v-list-item>
//查看所有人的订单
            showOrder() {
                jQuery.getJSON("/order/alllist", {},
                    function (result) {
                        if (result != null && result.data != null) {
                            app.orders = result.data;
                            // 显示订单列表窗体
                            app.status = 'ordersPage';
                        }
                    });
            },
<!-- 订单列表 -->
<v-simple-table v-show="status == 'ordersPage' && login.isLogin">
    <template v-slot:default>
        <thead>
        <tr>
            <th class="text-left">序号</th>
            <th class="text-left">用户</th>
            <th class="text-left">状态</th>
            <th class="text-left">时间</th>
            <th class="text-left">详情</th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="order in orders">
            <td>{{order.id}}</td>
            <td>{{order.uname}}</td>
            <td>
                <v-switch v-model="order.status" v-on:click="update(order.id,order.status)"></v-switch>
            </td>
            <td>{{order.createtime}}</td>
            <td>
                <v-btn color='primary' v-on:click="detail(order.id)">查看详情</v-btn>
            </td>
        </tr>
        </tbody>
    </template>
</v-simple-table>

修改订单状态

//管理员修改状态
update(oid, status) {
    //因为选中的这个状态在前端我们显示选中为true,不选中为false,所以此处需要用三元符进行一个选择
    status = status ? 1 : 0;
    jQuery.getJSON("/order/update", {"oid": oid, "status": status}, function (result) {
        if (result != null && result.data != null && result.data > 0) {
            alert("恭喜,状态修改成功");
        } else {
            alert("修改失败,请重试");
        }
    });
},

查看某个订单详情

//查看某个订单详情
detail(oid) {
    jQuery.getJSON("/detail/list", {"oid": oid}, function (result) {
        if (result != null && result.data != null) {
            app.curOrder = result.data;
            //显示订单详情页面
            app.showCurOrder = true;
        }
    });
},
<!--订单详情窗口-->
<v-row justify="center">
    <v-dialog v-model="showCurOrder" persistent max-width="600px">
        <v-simple-table>
            <template v-slot:default>
                <thead>
                <tr>
                    <th class="text-left">菜品</th>
                    <th class="text-left">价格</th>
                </tr>
                </thead>
                <tbody>
                <tr v-for="dish in curOrder">
                    <td>{{dish.dish.name}}</td>
                    <td>{{dish.dish.price}}</td>
                </tr>
                <tr>
                    <td>总金额: {{totalPrice()}}</td>
                    <td>
                        <v-btn color="primary" v-on:click="showCurOrder=false">关闭</v-btn>
                    </td>
                </tr>
                </tbody>
            </template>
        </v-simple-table>
    </v-dialog>
</v-row>
//计算某个订单详情的总价
totalPrice() {
    let money = 0;
    app.curOrder.forEach(item => {
        money += item.dish.price;
    });
    return money;
},

controller

查看所有订单

//管理员查看所有人列表信息
    @RequestMapping("/alllist")
    public ResponseBody<List<OrderInfo>> getAllList(HttpServletRequest request) {
        List<OrderInfo> orderinfo = null;
        orderinfo = orderInfoMapper.getAllList();
        return new ResponseBody<>(0, "", orderinfo);
    }

修改订单状态

//管理员修改用户订单的状态
@RequestMapping("/update")
public ResponseBody<Integer> updateStautus(int oid,int status) {
    int data = orderInfoMapper.update(oid,status);
    return new ResponseBody<>(0, "", data);
}

查看某个订单详情

@RequestMapping("/list")
public ResponseBody<List<OrderDetail>> getList(int oid){
    List<OrderDetail> list = orderDetailMapper.getList(oid);
    return new ResponseBody<>(0,"",list);
}

mapper

查看所有订单

//获取所有人的订单列表
public List<OrderInfo> getAllList();

修改订单状态

//修改订单的状态
 public int update(int oid,int status);

查看某个订单详情

public List<OrderDetail> getList(int oid);

xml

查看所有订单

<select id="getAllList" resultType="com.example.ordersys.model.OrderInfo">
    select o.*,u.username uname from orderinfo o left join userinfo u on o.uid=u.id order by o.id desc
</select>

注意这里我们依旧使用到了联表查询,左连接

修改订单状态

<update id="update">
    update orderinfo set status=#{status} where id=#{oid}
</update>

查看某个订单详情

<resultMap id="BaseResultMap" type="com.example.ordersys.model.OrderDetail">
        <result property="did" column="did"></result>
        <result property="oid" column="oid"></result>
        <association property="dish" columnPrefix="d_" resultMap="com.example.ordersys.mapper.DishMapper.BaseResultMap">
        </association>
    </resultMap>
    
    
<select id="getList" resultMap="BaseResultMap">
    select o.*,d.name d_name,d.price d_price from orderdetail o left join dish d on o.did=d.id
   where o.oid=#{oid}
</select>

这块的代码逻辑跟之前用户查看订单详情功能一样

退出登录功能

前端

<v-list-item link v-on:click="logout">
    <v-list-item-action>
        <v-icon>mdi-logout</v-icon>
    </v-list-item-action>
    <v-list-item-content>
        <v-list-item-title>退出登录</v-list-item-title>
    </v-list-item-content>
</v-list-item>
logout() {
    if (confirm("是否确认退出?")) {
        jQuery.getJSON("/user/logout", {}, function (result) {
            if (result != null && result.data != null && result.data > 0) {
                //退出成功
                alert("退出成功");
                //刷新当前页面
                location.href = location.href;
            } else {
                alert("抱歉,操作失败,请重试");
            }
        });
    }
},

controller

/**
 * 退出登录
 * @param request
 * @return
 */
@RequestMapping("/logout")
public ResponseBody<Integer> logOut(HttpServletRequest request) {
    int data = 0;
    HttpSession session = request.getSession(false);
    if (session != null && session.getAttribute(AppFinal.USERINFO_SESSION_KEY) != null) {
        session.removeAttribute(AppFinal.USERINFO_SESSION_KEY);
        data = 1;
    }
    session.removeAttribute(AppFinal.USERINFO_SESSION_KEY);
    return new ResponseBody<>(0, "", data);

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/49218.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Oracle表空间详细介绍

表空间概述 Oracle的表空间属于Oracle中的存储结构&#xff0c;是一种用于存储数据库对象(如&#xff1a;数据文件)的逻辑空间&#xff0c;是Oracle中信息存储的最大逻辑单元&#xff0c;其下还包含有段、区、数据块等逻辑数据类型。表空间是在数据库中开辟的一个空间&#xf…

GoEXP规则变更通知 l 信创额外奖励活动

一、规则变更 Goby 致力于打造高质量漏洞 EXP&#xff0c;每个环节的细节都不容忽视。为了提升大家在 Goby 上查看、使用 EXP 等环节的体验&#xff0c;我们针对 GoEXP 计划规则中的 EXP 参数部分提出规约。 参数名必须要⻅名思义&#xff0c;禁⽌使⽤套⽤。 反例&#xff1…

Mybatis-Plus--LambdaQueryChainWrapper--使用/实例

原文网址&#xff1a;Mybatis-Plus--LambdaQueryChainWrapper--使用/实例_IT利刃出鞘的博客-CSDN博客 简介 说明 本文用示例介绍Mybatis-Plus的LambdaQueryChainWrapper的用法。 这种用法是使用Mybatis-Plus进行查询最好用的方法&#xff0c;用过一次后就不会再想用其他写法了…

某有色金属集团主数据管理面临的问题和解决方案

某有色金属集团成立于2002年&#xff0c;出资人为省国资委&#xff0c;注册资金12.6亿元人民币。以有色金属、稀有金属、黄金资源开发为主&#xff0c;集地质勘查、采矿、选矿、冶炼、加工、科研设计、机械制造、建筑安装、商贸物流及物资进出口、房地产开发、物业管理为一体的…

获得认证标志证书VMC教程

Verified Mark Certificate(VMC)是由证书颁发机构颁发的用于验证徽标所有权的数字证书。在收到VMC之前&#xff0c;您的徽标必须是注册商标。 VMC验证您的组织是您品牌徽标的合法所有者。使用带有VMC的徽标有助于防止垃圾邮件发送者和其他恶意用户使用他们不拥有的品牌徽标。注…

Linux权限介绍

文章目录Linux权限介绍1. shell命令及原理2. Linux权限的概念3. Linux权限管理3.1 人&#xff08;用户&#xff09;3.2 事物属性(文件类型和访问权限)3.3 文件访问权限的相关设置方法3.3.1 chmod3.3.2 chown3.3.3 chgrp3.4 file指令3.5 目录权限3.6 默认权限3.7 粘滞位3.7.1. 了…

matlab学习笔记(七)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 matlab学习笔记&#xff08;七&#xff09;一、 LTI系统的响应impulse( ) 函数step( )函数lsim( )函数系统无初态时系统有初始状态时二、使用步骤A1&#xff1a;A2&#xff1…

Sentinel原理分析

1.概述 Sentinel(分布式系统的流量防卫兵)是阿里开源的一套用于服务容错的综合性解决方案; Sentinel是面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护等多个维度来帮助您保障微服务的稳定性; 本质要做的就是两件事: …

第2部分 路由器基本配置

目录 2.1 路由器及IOS 简介 2.1.1 路由器简介 2.1.2 IOS 简介 2.1.3 CDP 协议介绍 2.2 路由器基本配置命令汇总 2.1 路由器及IOS 简介 2.1.1 路由器简介 路由器能起到隔离广播域的作用&#xff0c;还能在不同网络间转发数据包。路由器实际上是一台特殊用途的计算机&#…

[论文阅读] Curriculum Semi-supervised Segmentation

[论文地址] [代码] [MICCAI 19] Abstract 本研究调查了半监督CNN分割的课程式策略&#xff0c;它设计了一个回归网络来学习图像级信息&#xff0c;如目标区域的大小。这些回归被用来有效地规范分割网络&#xff0c;约束未标记图像的softmax预测&#xff0c;使其与推断的标签分…

【 第五章 多表关系,多表查询,内连接,外连接,自连接,联合查询,子查询】

第五章 多表关系&#xff0c;多表查询&#xff0c;内连接&#xff0c;外连接&#xff0c;自连接&#xff0c;联合查询&#xff0c;子查询 1.多表关系&#xff1a; &#xff08;1&#xff09;一对多(多对一) 案例: 部门 与 员工的关系 关系: 一个部门对应多个员工&#xff0c;…

【springMVC_11_SpringMVC拦截器_ 拦截器的介绍】

1.什么是拦截器 SpringMVC提供了Intercepter拦截器机制&#xff0c;类似于Servlet当中的Filter过滤器&#xff0c;用于拦截用户的请求并作出相应的处理&#xff0c;比如通过拦截器来进行用户权限验证或者用来判断用户是否登录。SpringMVC拦截器是可插拔式的设计&#xff0c;需…

Linux学习笔记(二)

命令 目录中找文件&#xff1a;find压缩tar&#xff1a;tar -cvf xxx.tar 文件解压缩tar&#xff1a;tar -xvf xxx.tar解压缩.gz文件&#xff1a;tar -zxvf xxx.tar.gz压缩.bz2文件&#xff1a;tar -jcvf xxx.tar.bz2解压到指定目录&#xff1a;tar -C 指定目录压缩zip&#xf…

CIFAR-10 数据集简介

文章目录CIFAR-10 简介CIFAR-10 简介 官网&#xff1a;http://www.cs.toronto.edu/~kriz/cifar.html CIFAR-10和CIFAR-100是8000个万小图像数据集的标记子集。它们由Alex Krizhevsky, Vinod Nair和Geoffrey Hinton收集。 CIFAR-10数据集包含60000张32x32彩色图像&#xff0c…

2183440-36-8,APN-C3-PEG4-alkyne 性能稳定功能连接体

一、APN-C3-PEG4-alkyne物理数据&#xff1a; CAS&#xff1a;2183440-36-8 | 中文名&#xff1a;APN-C3-四聚乙二醇-炔基 |英文名&#xff1a; APN-C3-PEG4-alkyne 结构式&#xff1a; 二、APN-C3-PEG4-alkyne试剂反应原理&#xff1a; 西安凯新生物科技有限公司供应的&…

企业上云原来如此简单,华为云带你体验云上风采

随着云计算、大数据、物联网和人工智能等技术的发展&#xff0c;云计算已经成为企业发展不可或缺的基础设施。企业对数字化转型的需求越来越迫切&#xff0c;但由于自身系统无法满足复杂业务上云需求&#xff0c;企业同时也面临着 IT系统复杂、运维复杂等诸多挑战。 基于此种情…

enumerate(),plt绘图,保存json,cv2.resize,baseline

1.enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列&#xff0c;同时列出数据和数据下标&#xff0c;一般用在 for 循环当中。 enumerate(sequence, [start0]) >>>seasons [Spring, Summer, Fall, Winter] >>> list(e…

为什么解决文档管理问题的数字化战略能够推动盈利增长

为什么解决文档管理问题的数字化战略能够推动盈利增长 每一天&#xff0c;世界都变得更加数字化&#xff0c;在我们的个人生活中&#xff0c;这种变化是持续的。 企业如何跟上发展的步伐&#xff1f;答案是&#xff1a;进行改变完成工作的方式、时间和地点&#xff0c;并在整个…

【学习笔记71】数据代理、回调函数和回调地域

一、数据代理 new Proxy(参数一: 代理那个对象)const obj {name: QF001,age: 18}const res new Proxy(obj, {get (target, p) {/*** target 当前代理的那个对象, 在当前案例中就是obj* p proxy会自动遍历对象, 拿到对象每一个key*/return target[p];},set (target, p,…

新课程发布 | 如何用 7 分钟击破 Serverless 落地难点?

当前&#xff0c;Serverless 覆盖的技术场景正在不断变广。Serverless 已在微服务、在线应用、事件驱动、任务处理等众多场景被验证且广泛应用 。当你想要部署一个网站时&#xff0c;需要自己购买服务器并花费时间去维护&#xff0c;造成资源浪费不说&#xff0c;还要耗费精力。…