JavaWeb购物系统(六)购物车订单模块的实现

这篇具有很好参考价值的文章主要介绍了JavaWeb购物系统(六)购物车订单模块的实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

效果图

有订单时的效果图
JavaWeb购物系统(六)购物车订单模块的实现
无订单时的效果图
JavaWeb购物系统(六)购物车订单模块的实现
订单详情页
JavaWeb购物系统(六)购物车订单模块的实现

功能

  1. 生成订单
  2. 订单页的展示
  3. 查看订单详情

正文

说明

和购物车同样的,首先得知道我们的订单对应的哪个实体对象。一个用户可能有多条订单记录,一个订单里边可以包含多个商品(也可以理解为多个购物项)。理清这个逻辑之后,我们就可以得到两个实体:订单实体类详细的订单项
对应到界面上就是如下图:
JavaWeb购物系统(六)购物车订单模块的实现

order.jsp(订单页)

<%@ page import="com.service.OrderService" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%@ page import="com.myUtil.ProcessUtil" %>
<%@ page import="com.entity.Order" %>
<%@ page import="java.util.List" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
  Created by IntelliJ IDEA.
  User: huawei
  Date: 2022/10/22
  Time: 20:02
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>我的订单</title>
    <!--Bootstrap5 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/css/bootstrap.min.css">
    <%--icon图标--%>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css">
    <!--  popper.min.js 用于弹窗、提示、下拉菜单 -->
    <script src="https://cdn.staticfile.org/popper.js/2.9.3/umd/popper.min.js"></script>
    <!-- 最新的 Bootstrap5 核心 JavaScript 文件 -->
    <script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
</head>
<body>
<%
    OrderService orderService = new OrderService();
    String userId = ProcessUtil.getUserIdBySessionId(session);
    List<Order> orderList= orderService.showAllOrder(userId);
    if (orderList!=null && orderList.size()!=0){
        session.setAttribute("orderList",orderList);
    }
%>
<nav class="navbar-expand-lg navbar navbar-dark bg-primary">
    <div class="container-fluid ">
        <a class="navbar-brand" href="#">我的订单</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNavDropdown">
            <ul class="navbar-nav">
                <li class="nav-item">
                    <a class="nav-link active" aria-current="page" href="/MyProject/index.jsp">Home</a>
                </li>
            </ul>
        </div>
    </div>
</nav>
<c:if test="${empty sessionScope.orderList}">
    <div class="container" >
        <div class="card position-relative" style="margin: 50px;height: 280px;background: #ffffff url(img/CartBackground.png) no-repeat; background-position: center left;">
            <div class="position-absolute top-50 start-50 translate-middle">
                <h7>
                    您还未购买过任何商品哦!赶紧行动吧!您可以:
                </h7><br>
                <a class="btn btn-primary btn-lg" href="/MyProject/index.jsp">购物</a>
            </div>
        </div>
    </div>
</c:if>
<c:if test="${!empty sessionScope.orderList}">
    <div class="container">
        <div class="card">
            <table class="table table-hover text-center">
                <tr>
                    <td>订单号</td>
                    <td>下单时间</td>
                    <td>总价</td>
                    <td>状态</td>
                    <td>详情</td>
                </tr>
                <c:forEach items="${sessionScope.orderList}" var="order">
                    <tr style="vertical-align: middle !important;text-align: center;">
                        <td>
                            <%--<img style="width: 100px;height: 100px" src="${or}"/>--%>
                            <span>${order.id}</span>
                        </td>
                        <td>
                            <%--分割下单时间--%>
                            <c:set value="${fn:split(order.create_time,'T')}" var="time"></c:set>
                            <c:forEach var="tm" items="${time}">
                                ${tm}
                            </c:forEach>
                        </td>
                        <td>${order.price}</td>
                        <td>0</td>
                        <td><a type="submit" class="btn btn-danger" href="/MyProject/orderDetail.jsp?orderId=${order.id}">查看</a></td>
                    </tr>
                </c:forEach>
            </table>
            <div class="row justify-content-between">


            </div>
        </div>
    </div>
</c:if>
</body>
</html>
订单的展示

这里通过在jsp页面,调用service层showAllOrder()来获取所有的订单列表。然后通过for-Each来将列表的每条信息渲染到前端页面

订单的查看

和前面几节讲的留言删除删除购物项思路一样,通过携带唯一标识ID(下单时间的毫秒数)来查看对应订单的详细信息。因为查看订单详情需要跳转页面,所有我们这里采用<a></a>标签来进行跳转。相关代码:

<td>
	<a type="submit" class="btn btn-danger" href="/MyProject/orderDetail.jsp?orderId=${order.id}">查看</a>
</td>

orderDetail.jsp(订单详情页)

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="com.entity.OrderItem" %>
<%@ page import="com.service.OrderItemService" %>
<%@ page import="java.util.List" %>
<%@ page import="com.service.OrderService" %>
<%@ page import="com.myUtil.ProcessUtil" %><%--
  Created by IntelliJ IDEA.
  User: huawei
  Date: 2022/10/22
  Time: 22:40
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>订单详情页</title>
    <!--Bootstrap5 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/css/bootstrap.min.css">
    <%--icon图标--%>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css">
    <!--  popper.min.js 用于弹窗、提示、下拉菜单 -->
    <script src="https://cdn.staticfile.org/popper.js/2.9.3/umd/popper.min.js"></script>
    <!-- 最新的 Bootstrap5 核心 JavaScript 文件 -->
    <script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
</head>
<body>
<%
    OrderItemService orderItemService = new OrderItemService();
//    String orderId = (String)session.getAttribute("orderId");
//    if (orderId==null){
        // 当用户重新登录之后/重启服务器,seesion域中会清空orderId。所以需要
      String  orderId = request.getParameter("orderId");
//    }
    List<OrderItem> orderItems = orderItemService.showAllOrderItem(orderId);
    if (orderItems !=null && orderItems.size()!=0){
        session.setAttribute("orderItems",orderItems);
    }
%>
<nav class="navbar-expand-lg navbar navbar-dark bg-primary">
    <div class="container-fluid ">
        <a class="navbar-brand" href="#">订单详情页</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNavDropdown">
            <ul class="navbar-nav">
                <li class="nav-item">
                    <a class="nav-link active" aria-current="page" href="/MyProject/index.jsp">Home</a>
                </li>
            </ul>
        </div>
    </div>
</nav>
<c:if test="${!empty sessionScope.orderItems}">
    <div class="container">
        <div class="card">
            <table class="table table-hover text-center">
                <tr>
                    <td>订单号</td>
                    <td>商品名称</td>
                    <td>价格</td>
                    <td>数量</td>
                    <td>总价格</td>
                </tr>
                <c:forEach items="${sessionScope.orderItems}" var="orderItem">
                    <tr style="vertical-align: middle !important;text-align: center;">
                        <td>${orderItem.order_id}</td>
                        <td>
                            <img style="width: 100px;height: 100px" src="${orderItem.img}"/>
                            <span>${orderItem.name}</span>
                        </td>
                        <td>${orderItem.price}</td>
                        <td>${orderItem.count}</td>
                        <td>${orderItem.total_price}</td>
                    </tr>
                </c:forEach>
            </table>

        </div>
    </div>
</c:if>
</body>
</html>
订单详情的展示

在上边查看详情页按钮的代码中可以看到,跳转的不是Controller层,而是跳转到了orderDetail.jsp页面。在详情页面,通过请求携带的订单Id,来获取数据库的中的订单项数据

不知道大家到这里会不会很奇怪?订单项是一个对象,订单也是一个对象。我们的订单和订单项的展示,都需要从数据库来获取,那么这两个对象是什么时候存储到数据库中的呢?

别急。下边就是答案:
JavaWeb购物系统(六)购物车订单模块的实现
当我们在购物车中点击结算按钮的时候,他就会生成订单对象以及和它对应的订单项
我们这里解释一下,它的前后端是如何处理的:

// 结算
$("#settlement").click(
    function () {
        $.post(
            "/MyProject/orderProcessServlet",
            {
                method: ""
            },
            function (data) {
                if ("success" == data){
                    alert("订单生成成功!");
                    location.reload(true);
                }
            },
            "json"
        )
    }
)

这段js代码在上一章节中,因为它属于购物车部分。是发送结算请求。请求地址是/orderProcessServlet,即我们的订单对应的Controller层

OrderProcessServlet(订单处理层)

package com.controller;
import com.entity.*;
import com.google.gson.Gson;
import com.myUtil.JdbcUtil;
import com.myUtil.ProcessUtil;
import com.service.OrderService;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class OrderProcessServlet extends HttpServlet {
    private OrderService orderService = new OrderService();
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        HttpSession session = request.getSession();
        Cart cart = (Cart) session.getAttribute("cart");
        String userId = ProcessUtil.getUserIdBySessionId(session);
        if (cart==null || cart.getItems().size()==0){
            response.sendRedirect("/MyProject/index.jsp");
            return;
        }
        if (cart!=null){
            // 对生成订单进行事务控制
            String orderId = null;
            try {
                orderId = orderService.saveOrder(cart, Integer.parseInt(userId));
                JdbcUtil.commit();
                session.setAttribute("orderId",orderId);
                response.getWriter().write(new Gson().toJson("success"));
            } catch (Exception e) {
                // 如果出错事务回滚
                JdbcUtil.rollback();
                e.printStackTrace();
            }
        }

    }
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        doPost(request, response);
    }
}

orederService(订单处理的业务层)

package com.service;
import com.dao.GoodsDao;
import com.dao.OrderDao;
import com.dao.OrderItemDao;
import com.entity.*;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;

public class OrderService {
    private OrderDao orderDao = new OrderDao();
    private OrderItemDao orderItemDao = new OrderItemDao();
    private GoodsDao goodsDao = new GoodsDao();
    // 生成订单
    public String saveOrder(Cart cart, Integer userId){
        // 生成订单号
        String orderId = String.valueOf(System.currentTimeMillis());
        // 订单生成时间
        LocalDateTime createTime = LocalDateTime.now();
        Order order = new Order(orderId,createTime,cart.getTotalPrice(),0,userId);
        // 保存order表到数据库
        orderDao.addOrder(order);
        // 构建orderItem,并保存到数据库
        HashMap<Integer, ShopCarItem> items = cart.getItems();
        for (Integer goodId : items.keySet()) {
            ShopCarItem item = items.get(goodId);
            OrderItem orderItem =
                    new OrderItem(null, item.getImg(), item.getGoodsName(), item.getPrice(), item.getNumber(), item.getTotalPrice(), orderId);
            orderItemDao.addOrderItem(orderItem);
            // 得到商品信息
            Goods goods = goodsDao.showDataById(String.valueOf(goodId));
            // 更新库存
            goods.setInventory(goods.getInventory() - item.getNumber());
            // 更新到数据库
            goodsDao.updateStock(goods);
        }
        // 清空购物车
        cart.removeAll();
        return orderId;
    }

    // 显示所有订单
    public List<Order> showAllOrder(String userId){
        return orderDao.showAllOrder(userId);
    }
}

接着上边的逻辑,当生成订单请求发过来之后,在这Controller层调用Service层saveOrder()进行了订单的生成,而且在Service层我们进行了订单保存订单项的保存。而且我们注意到saveOrder()的参数是Cart购物车对象用户Id。因为订单和订单项的所有信息都是从购物车来获取的,而且每个订单得有对应的用户(我们得保证自己的订单不能出现在别人的页面上,对吧^_^)。
当然生成订单之后还得清空购物车。

orderItemService

package com.service;

import com.dao.OrderItemDao;
import com.entity.OrderItem;

import java.util.List;

public class OrderItemService {
    private OrderItemDao orderItemDao = new OrderItemDao();
    // 显示所有订单项
    public List<OrderItem> showAllOrderItem(String orderId){
        return  orderItemDao.showAllOrderItem(orderId);
    }

}

orderDao

package com.dao;

import com.entity.Order;

import java.util.List;

public class OrderDao extends BasicDao<Order> {
    // 生成订单
    public Boolean addOrder(Order order){
        String sql = "INSERT INTO `order` VALUES('"+order.getId()+"','"+order.getCreate_time()+"',"+order.getPrice()+","+order.getStatus()+","+order.getMember_id()+")";
        return dmlData(sql);
    }
    // 显示所有订单
    public List<Order> showAllOrder(String userId){
        String sql = "SELECT * FROM `order` WHERE `member_id`='" + userId + "'";
        List<Order> orders = queryMulti(sql, Order.class);
        if (orders!=null){
            return orders;
        }
        return null;
    }
}

orderItemDao

package com.dao;

import com.entity.OrderItem;

import java.util.List;

public class OrderItemDao extends BasicDao<OrderItem>{
    // 添加订单项
    public Boolean addOrderItem(OrderItem orderItem){
        String sql = "INSERT INTO `order_item` VALUES(NULL,'"+ orderItem.getImg() +"','"+ orderItem.getName() + "',"+ orderItem.getPrice() +","+ orderItem.getCount() +","+ orderItem.getTotal_price() +",'"+ orderItem.getOrder_id() +"')";
        return dmlData(sql);
    }

    // 显示所有订单项
    public List<OrderItem> showAllOrderItem(String orderId){
        String sql = "SELECT * FROM `order_item` WHERE `order_id`='"+ orderId +"'";
        List<OrderItem> orderItems = queryMulti(sql, OrderItem.class);
        if (orderItems != null){
            return orderItems;
        }
        return null;
    }
}

order(订单实体类)

订单实体类拥有属性:

  1. 订单号(订单结算的毫秒时间)
  2. 订单生成时间
  3. 订单金额
  4. 订单状态(这里我们没有太多的功能,所以默认是0)
  5. 订单所属者(每个订单属于哪个用户)
package com.entity;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class Order {
    // 订单号
    private String id;
    // 订单生成时间
    private LocalDateTime create_time;
    // 订单金额
    private BigDecimal price;
    // 订单状态
    private Integer status;
    // 该订单对应的用户id
    private Integer member_id;

    public Order() {
    }

    public Order(String id, LocalDateTime create_time, BigDecimal price, Integer status, Integer member_id) {
        this.id = id;
        this.create_time = create_time;
        this.price = price;
        this.status = status;
        this.member_id = member_id;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public LocalDateTime getCreate_time() {
        return create_time;
    }

    public void setCreate_time(LocalDateTime create_time) {
        this.create_time = create_time;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public Integer getMember_id() {
        return member_id;
    }

    public void setMember_id(Integer member_id) {
        this.member_id = member_id;
    }

    @Override
    public String toString() {
        return "Order{" +
                "id='" + id + '\'' +
                ", create_time=" + create_time +
                ", price=" + price +
                ", status=" + status +
                ", member_id=" + member_id +
                '}';
    }
}

orderItem(订单项实体类)

订单项的实体类拥有的属性:

  1. 订单项唯一的标识Id
  2. 商品图片
  3. 商品的价格
  4. 商品数量
  5. 订单项的总价格
  6. 订单项的所属的订单(订单项都是从属于某一个订单)
package com.entity;

import java.math.BigDecimal;

public class OrderItem {
    // 订单项的自增ID
    private Integer id;
    // 商品图片
    private String img;
    // 商品名
    private String name;
    // 商品价格
    private BigDecimal price;
    // 商品数量
    private Integer count;
    // 订单项的总价
    private BigDecimal total_price;
    // 对应的订单号
    private String order_id;

    public OrderItem() {
    }

    @Override
    public String toString() {
        return "OrderItem{" +
                "id=" + id +
                ", img='" + img + '\'' +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", count=" + count +
                ", total_price=" + total_price +
                ", order_id='" + order_id + '\'' +
                '}';
    }

    public String getImg() {
        return img;
    }

    public void setImg(String img) {
        this.img = img;
    }

    public OrderItem(Integer id, String img, String name, BigDecimal price, Integer count, BigDecimal total_price, String order_id) {
        this.id = id;
        this.img = img;
        this.name = name;
        this.price = price;
        this.count = count;
        this.total_price = total_price;
        this.order_id = order_id;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }

    public BigDecimal getTotal_price() {
        return total_price;
    }

    public void setTotal_price(BigDecimal total_price) {
        this.total_price = total_price;
    }

    public String getOrder_id() {
        return order_id;
    }

    public void setOrder_id(String order_id) {
        this.order_id = order_id;
    }

}

order表的设计

列名 数据类型 长度 主键? 非空? 自增?
id varchar 64
create_time datetime
price decimal 11,2
statue tinyint 32
member int

orderItem表的设计

列名 数据类型 长度 主键? 非空? 自增?
id int
img varchar 500
name varchar 500
price decimal 11,2
count int
total_price decimal 11,2
order_id varchar 64

这里我们得保证实体类的属性名要和对应表的字段名保持一致!!!文章来源地址https://www.toymoban.com/news/detail-445497.html

到了这里,关于JavaWeb购物系统(六)购物车订单模块的实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JavaWeb购物车项目

    目录 项目前提 数据库的创建 用户表 商品表 eclipse进行创建包和类: 主要实现功能 1、购物车用户登录 2、商品显示 3、购物车添加商品总数和价格的计算 1、购物车并不是一直放数据库 2、选择使用的技术: session:(购物车项目使用session) 好处:快(放在内存当中),存对象的

    2024年02月05日
    浏览(50)
  • JavaWeb 购物车项目(一)

    今天的学习主要是完成一个购物车项目,该项目中使用servlet完成,对于不知道servlet不知道如何使用的去看 servlet的使用 该篇文章,该文章中有教大家如何使用servlet。 目录 一.项目所需表  二.购物车项目实操  1.登录操作 2.首页操作 购物车数据操作 :CarServlet, 我们在点击首

    2024年02月04日
    浏览(49)
  • JavaWeb购物车项目 思路&拓展&综合提升

    目录  一、实现思路 二、JSP 页面实现(临时性购物车项目)         第一部分:images(图片)         第二部分:SQL代码         第三部分:代码                  实体层(entity):                         1.entity 包 (package com.zking.goods.entity;)   

    2024年02月09日
    浏览(55)
  • JavaWeb(10)——前端综合案例4(购物车示例)

           购物车需要展示一个已加入购物车的商品列表,包含商品名称、商品单价、购买数量和操作 等信息,还需要实时显示购买的总价。其中购买数量可以增加或减少,每类商品还可以从购物车中移除。最终实现的效果大致如图所示。 基础版 plus版              先在

    2024年02月05日
    浏览(50)
  • 【业务功能篇97】微服务-springcloud-springboot-电商购物车模块-获取当前登录用户的购物车信息

      我们需要先创建一个cart的微服务,然后添加相关的依赖,设置配置,放开注解。 然后属性文件中的配置 然后再添加配置中心的配置:bootstrap.yml文件 放开注册中心的注解   首先在windows中的host指定对应域名 拷贝对应的静态资源到Nginx的static/cart目录中 然后修改Nginx的配

    2024年02月09日
    浏览(74)
  • 【javaweb+springboot】旅游网页面设计(主购物车功能)——前后端分离+服务端客户端增删改查(完整代码+文档)

    一、项目背景 由于疫情原因,张家界旅游业受到很大的影响,为了促进旅游业的发展,吸引更多游客来到张家界旅游,帮助游客更好地了解张家界,创建张家界旅游网,推进旅游发展大会的开展,展示当地风土人情。景区推荐和酒店预定使得游客出行更加的方便,通过游客留

    2024年02月09日
    浏览(44)
  • Vue项目商品购物车前端本地缓存逻辑(适用H5/ipad/PC端)——前端实现购物车删除商品、购物车增减数量,清空购物车功能

    Vue3 + Vite + Ts开源后台管理系统模板 基于ElementUi或AntdUI再次封装基础组件文档 基于Element-plus再次封装基础组件文档(vue3+ts)

    2024年02月12日
    浏览(52)
  • 给你一个购物车模块,你会如何设计测试用例?【测试用例设计】

    测试购物车 从使用场景上,把自己想象成一个使用购物车的人,模拟流程,可以主要从两个方面进行考虑: 涉及操作:增(添加商品)删(删除商品)改(编辑、跳转商品)查(检查金额、数目、优惠明细)+商品支付 涉及交互:购物车与用户登录状态的交互,购物车与商品

    2024年01月24日
    浏览(60)
  • js实现购物车

    ### 嘎嘎原生,看就完了 ### # # html部分 ### css部分 ### js部分

    2024年01月21日
    浏览(54)
  • 购物车程序实现教程

    在本教程中,我们将实现一个购物车程序,实现在界面中以列表的形式显示购物车的商品信息。商品信息包含商品名称,价格和数量,并能实现对应的增删改查操作。我们将使用 Android Studio 和 SQLite 数据库来完成这个任务。 我们的购物车程序由以下四个主要类组成: MainAct

    2024年02月04日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包