项目实战系列三: 家居购项目 第四部分

news2024/11/13 10:42:11

购物车

  • 🌳购物车
    • 🍆显示购物车
    • 🍆更改商品数量
    • 🍆清空购物车&&删除商品
  • 🌳生成订单

🌳购物车

需求分析
1.会员登陆后, 可以添加家居到购物车
2.完成购物车的设计和实现
3.每添加一个家居,购物车的数量+1, 并显示

程序框架图

在这里插入图片描述

1.新建src/com/zzw/furns/entity/CartItem.java, CartItem-家居项模型

/**
 * 购物车的一项就是某个家居数据
 * @author 赵志伟
 * @version 1.0
 */
@SuppressWarnings({"all"})
public class CartItem {
    private Integer id;//编号
    private String name;//家居名
    private Integer count;//数量
    private BigDecimal price;//单价
    private BigDecimal totalPrice;//总价
    private String imagePath;//家具图片

    public CartItem() {
    }

	//有参构造器, getter, setter方法
}

2.Cart数据模型

在这里插入图片描述

3.新建src/com/zzw/furns/entity/Cart.java, 这里默认添加的数量是1

//Cart就是购物车, 包含多个CartItem
public class Cart {
    //使用HashMap来保存
    private Map<Integer, CartItem> items = new HashMap<>();

    public boolean isEmpty() {
        return items.size() == 0;
    }

    //Cart表示购物车, items表示购物车明细
    //添加家居[CartItem]到Cart
    public void addItem(CartItem cartItem) {
        CartItem item = items.get(cartItem.getId());//得到购物车里的商品项

        if (item == null) {//说明当前购物车还没有这个cartItem
            items.put(cartItem.getId(), cartItem);
        } else {//购物车中有这个cartItem
            item.setCount(item.getCount() + 1);//数量加1
            //修改总价
            //item.getPrice() => BigDecmal
            //item.getCount() => Integer
            item.setTotalPrice(item.getPrice().multiply(new BigDecimal(item.getCount())));
        }
    }

    public Integer getTotalCount() {
        Integer totalCount = 0;//购物车商品的总数量
        Collection<CartItem> cartItems = items.values();
        for (CartItem cartItem : cartItems) {
            totalCount += cartItem.getCount();
        }
        return totalCount;
    }
    
    /**
     * 返回购物车的总价
     * @return
     */
    public BigDecimal getCartTotalPrice() {

        BigDecimal cartTotalPrice = new BigDecimal(0);
        //遍历我们的items
        Set<Integer> keys = items.keySet();
        for (Integer id : keys) {
            CartItem item = items.get(id);
            //提醒, 一定要包add后的值, 重新赋给 cartTotalPrice, 这样才是累加.
            cartTotalPrice = cartTotalPrice.add(item.getTotalPrice());
        }

        return cartTotalPrice;
    }
    
    //todo  setter, getter方法, toString方法
}

4.测试src/com/zzw/furns/test/CartTest.java

public class CartTest {
    @Test
    public void addItem() {
        Cart cart = new Cart();
        cart.addItem(new CartItem(1, "java从入门到精通", 1, new BigDecimal(1000), new BigDecimal(1000)));
        cart.addItem(new CartItem(1, "java从入门到精通", 1, new BigDecimal(1000), new BigDecimal(1000)));
        cart.addItem(new CartItem(2, "数据结构与算法", 1, new BigDecimal(100), new BigDecimal(100)));
        System.out.println(cart);
    }
}

5.创建src/com/zzw/furns/web/CartServlet.java
cart是个引用, cart内容变了, session中也会跟着变

@WebServlet(urlPatterns = "/cartServlet")
public class CartServlet extends BasicServlet {

    private FurnService furnService = new FurnServiceImpl();
    
    //添加一个添加家居到购物车的方法
    protected void addItem(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int id = DataUtils.parseInt(request.getParameter("id"), 1);//家居id
        //根据id获取对应的家居信息
        Furn furn = furnService.queryFurnById(id);
        //先把正常的逻辑走完, 再处理异常的情况

        HttpSession session = request.getSession();
        Cart cart = (Cart) session.getAttribute("cart");
        //得到购物车 有可能是空的,也有可能是上次的
        if (cart == null) {
            cart = new Cart();
            session.setAttribute("cart", cart);
        }
        //构建一条家居明细: id,家居名,数量, 单价, 总价
        //count类型为Integer, 不赋值默认值为null
        CartItem cartItem = new CartItem(id, furn.getName(), 1, furn.getPrice(), furn.getPrice(), furn.getImagePath());
        //将家居明细加入到购物车中. 如果家居id相同,数量+1;如果是一条新的商品,那么就新增
        cart.addItem(cartItem);
        System.out.println("cart= " + cart);

        String referer = request.getHeader("referer");
        response.sendRedirect(referer);
    }
}

6.首页获取id请求后台

<button furnId="${furn/id}" title="Add To Cart" class="add-to-cart">Add
    To Cart
</button>
<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
    window.onload = function () {
        $("button[title='Add To Cart']").click(function () {
            window.location.href = "cartServlet?action=addItem&id=" + $(this).attr("furnId");
        })
    }
</script>

7.首页购买的商品总数量 - totalCount会默认调用getTotalCount方法

<a href="#offcanvas-cart"
   class="header-action-btn header-action-btn-cart pr-0">
    <i class="icon-handbag"> 购物车</i>
    <span class="header-action-num">${sessionScope.cart.totalCount}</span>
</a>

8.Cart类getTotalCount方法 - 错误写法
正确写法 - totalCount必须是局部变量, 否则会造成累加

public class Cart {

    private Integer totalCount = 0;//1 3 3
    //如果totalCount是全局变量, 将遵循这样的增长方式
    
    //次数   购物车数量   totalCount(=totalCount+购物车数量)
    // 1        1         1
    // 2        2         3
    // 3        3         6
    // 4        4         10
    // 5        5         15
    // 6        6         21
    // 7        7         28
    public Integer getTotalCount() {
        Collection<CartItem> cartItems = items.values();
        for (CartItem cartItem : cartItems) {
            totalCount += cartItem.getCount();
        }
        return totalCount;
    }
}

1.HashMap的数据实际上是存在HashMap$Node中的, Node是HashMap的内部类
2.keySet里的key, 实际上只是引用, 指向了HashMap$Node<k, v>对象中的k, 真正的key值是保存在HashMap的Node内部类中的(HashMap$Node)

🍆显示购物车

需求分析
1.查看购物车, 可以显示如下信息
2.选中了哪些家居, 名称, 数量, 金额
3.统计购物车共多少商品, 总价多少

程序框架图

在这里插入图片描述

代码实现
1.从资源包上传文件web/views/cart/cart.jsp

2.web/views/customer/index.jsp跳转购物车页面无响应 - 排错技巧展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

定位

在这里插入图片描述

3.显示家居项

<tbody>
<%--找到显示购物车项,  进行循环的items--%>
<c:if test="${not empty sessionScope.cart.items}">
    <%--
         1.sessionScope.cart.items => 取出的是HashMap<Integer, CartItem>
         2.所以通过foreach标签取出的每一个对象, 即entry是 HashMap<Integer, CartItem>的 k-v
         3.var其实就是 entry
         4.所以要取出cartItem对象, 是通过 entry.value取出
    --%>
    <c:forEach items="${sessionScope.cart.items}" var="entry">
        <tr>
            <td class="product-thumbnail">
                <a href="#"><img class="img-responsive ml-3"
                                 src="${entry.value.imagePath}"
                                 alt=""/></a>
            </td>
            <%--隐藏域--%>
            <td hidden="hidden" class="product-name"><a href="#">${entry.key}</a></td>
            <td class="product-name"><a href="#">${entry.value.name}</a></td>
            <td class="product-price-cart"><span class="amount">$${entry.value.price}</span>
            </td>
            <td class="product-quantity">
                <div class="cart-plus-minus">
                    <input class="cart-plus-minus-box" type="text" name="qtyButton"
                           value="${entry.value.count}"/>
                </div>
            </td>
            <td class="product-subtotal">$${entry.value.totalPrice}</td>
            <td class="product-remove">
                <a href="#"><i>class="icon-close"></i></a>
            </td>
        </tr>
    </c:forEach>
</c:if>
</tbody>

4.显示底部统计数据

<div class="row">
    <div class="col-lg-12">
        <div class="cart-shiping-update-wrapper">
            <h4>共${sessionScope.cart.totalCount}件商品 总价 ${sessionScope.cart.totalPrice}元</h4>
            <div class="cart-shiping-update">
                <a href="#">购 物 车 结 账</a>
            </div>
            <div class="cart-clear">
                <button>继 续 购 物</button>
                <a href="#">清 空 购 物 车</a>
            </div>
        </div>
    </div>
</div>

🍆更改商品数量

需求分析
1.进入购物车, 可以修改购买数量
2.更新该商品项的金额
3.更新购物车商品数量和总金额

程序框架图

在这里插入图片描述

1.修改Cart购物车类

/**
 * 修改指定的CartItem的数量和总价, 根据传入的id 和 count
 * @param id
 * @param count
 */
public void updateCount(int id, int count) {//传进来的更新后的数量
    CartItem cartItem = items.get(id);
    if (cartItem != null) {//如果得到cartItem
        //先更新数量
        cartItem.setCount(count);
        //再更新总价
        cartItem.setTotalPrice(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())));
        //set方法有可能对count进行了二次处理, 所里这里用getCount()比较安全
    }
}

2.修改src/com/zzw/furns/web/CartServlet.java,增加方法updateCount

/**
     * 更新某个cartItem的数量, 即更新购物车
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    protected void updateCount(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int id = DataUtils.parseInt(req.getParameter("id"), 0);//家居id[默认0, 即使传错也不会影响数据]
        int count = DataUtils.parseInt(req.getParameter("count"), 1);//更新后的数量

        //获取session中的购物车
        HttpSession session = req.getSession();
        Cart cart = (Cart) session.getAttribute("cart");
        if (cart != null) {
            cart.updateCount(id, count);
        }
        //回到请求更新购物车的原页面
        String referer = req.getHeader("referer");
        resp.sendRedirect(referer);
    }

3.修改web/views/cart/cart.jsp

<%--某个js文件对 cart-plus-minus 做了事件处理--%>
<div class="cart-plus-minus" furnId="${entry.value.id}">
    <input class="cart-plus-minus-box" type="text" name="qtybutton"
           value="${entry.value.count}"/>
</div>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.修改web/views/cart/cart.jsp

<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
    window.onload = function () {
        var CartPlusMinus = $(".cart-plus-minus");
        CartPlusMinus.prepend('<div class="dec qtybutton">-</div>');
        CartPlusMinus.append('<div class="inc qtybutton">+</div>');
        $(".qtybutton").on("click", function() {
            var $button = $(this);
            var oldValue = $button.parent().find("input").val();
            if ($button.text() === "+") {
                var newVal = parseFloat(oldValue) + 1;
            } else {
                // Don't allow decrementing below zero
                if (oldValue > 1) {
                    var newVal = parseFloat(oldValue) - 1;
                } else {
                    newVal = 1;
                }
            }
            $button.parent().find("input").val(newVal);

            //在这里书写我们的代码
            var furnId = $button.parent().attr("furnId");
            //在这里发出修改购物车的请求
            location.href = "cartServlet?action=updateCount&id=" + furnId + "&count=" + newVal;
        });
    }
</script>

🍆清空购物车&&删除商品

需求分析
1.进入购物车, 可以删除某商品
2.可以清空购物车
3.要求给出适当的确认信息

程序框架图

在这里插入图片描述

应用实例-删除商品

1.修改Cart购物车类

/**
 * 根据传入的id, 删除指定的购物车项
 * @param id
 */
public void deleteItem(int id) {
    items.remove(id);
}

2.修改src/com/zzw/furns/web/CartServlet.java,增加方法delItem

protected void delItem(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //为了防止接收的id转化成数字时报错, 在工具类DataUtils中写一个方法
    int id = DataUtils.parseInt(req.getParameter("id"), 0);

    HttpSession session = req.getSession();
    Cart cart = (Cart) session.getAttribute("cart");
    if (cart != null) {
        cart.deleteItem(id);
    }
    //返回到请求删除购物车的页面
    String referer = req.getHeader("referer");
    resp.sendRedirect(referer);
}

3.修改web/views/cart/cart.jsp

$(".product-remove").click(function () {
    var furnName = $(this).attr("furnName");
    return confirm("确定要删除 " + furnName + " 家居项吗?");
})
<td class="product-remove" furnName="${entry.value.name}">
    <a href="cartServlet?action=delItem&id=${entry.value.id}">
        <i class="icon-close"></i>
    </a>
</td>

清空购物车

1.修改Cart购物车类

//清空购物车
public void clear() {
    items.clear();
}

2.修改src/com/zzw/furns/web/CartServlet.java,增加方法clear

protected void clear(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //清空购物车
    Cart cart = (Cart) req.getSession().getAttribute("cart");
    if (cart != null) {
        cart.clear();
    }
    String referer = req.getHeader("referer");
    resp.sendRedirect(referer);
}

3.修改web/views/cart/cart.jsp

//清空购物车
$("a:contains('清 空 购 物 车')").click(function () {
    return confirm("确定要清空购物车吗?");
})
<a href="cartServlet?action=clear">清 空 购 物 车</a>

🌳生成订单

需求分析
1.进入购物车, 点击购物车结账
2.生成订单和订单项, 并更新商品的销量和库存
3.如果会员没有登陆, 先进入登陆页面, 完成登陆后再结账

程序框架图

在这里插入图片描述

1.创建order表

-- 创建家居网购需要的数据库和表
-- 删除数据库
DROP DATABASE IF EXISTS home_furnishing;

-- 删除表
DROP TABLE `order`;

-- 创建数据库
CREATE DATABASE home_furnishing;

-- 切换
USE home_furnishing;

-- 创建订单表
-- 每个字段应当使用 not null 来约束
-- 字段类型的设计, 应当和相关联表的字段类型相对应
-- 是否需要使用外键? 
-- 1.需要[可以从db层保证数据的一致性(早期hibernate框架要求必须使用外键)]
-- 2.不需要[外键对效率有影响, 应当从程序的业务层保证数据的一致性(推荐)]
CREATE TABLE `order` (
	id VARCHAR(60) PRIMARY KEY, -- 订单编号
	create_time DATETIME NOT NULL,-- 年月日 时分秒
	price DECIMAL(10,2) NOT NULL,-- 订单价格
	`status` TINYINT NOT NULL, -- 订单状态(1未发货 2已发货 3已结账)
	member_id INT NOT NULL -- 谁的订单
)CHARSET utf8 ENGINE INNODB;

2.创建order_item表

-- 创建家居网购需要的数据库和表
-- 删除数据库
DROP DATABASE IF EXISTS home_furnishing;

-- 删除表
DROP TABLE order_item;

-- 创建数据库
CREATE DATABASE home_furnishing;

-- 切换
USE home_furnishing;

-- 创建订单明细表
CREATE TABLE order_item (
	id INT PRIMARY KEY AUTO_INCREMENT, -- 订单明细id
	`name` VARCHAR(32) NOT NULL,-- 家居名
	`count` INT UNSIGNED NOT NULL,-- 数量
	price DECIMAL(10, 2) NOT NULL,-- 价格
	total_price DECIMAL(10, 2) NOT NULL,-- 订单项的总价格
	order_id VARCHAR(60) NOT NULL -- 订单编号
)CHARSET utf8 ENGINE INNODB;

3.新建实体类src/com/zzw/furns/entity/OrderItem.java, 订单明细表

public class OrderItem {
  private Integer id;
  private String name;
  private Integer count;
  private BigDecimal price;
  private BigDecimal totalPrice;
  private String orderId;

  public OrderItem() {
  }
  //有参构造器
  //getter方法, setter方法, toString方法
}

4.新建实体类src/com/zzw/furns/entity/Order.java, 订单表

public class Order {
  private String id;
  private Date createTime;
  private BigDecimal price;
  private Integer status;
  private Integer memberId;
  
  private List<OrderItem> items = new ArrayList<>();

  //计算订单的商品数, 供前端EL表达式使用
  public Integer getTotalCount() {
    Integer totalCount = 0;

    for (OrderItem orderItem : items) {
      totalCount += orderItem.getCount();
    }
    return totalCount;
  }
  
  //无参构造器
  public Order() {
  }
  //有参构造器
  //getter方法, setter方法, toString方法
}

5.新建src/com/zzw/furns/dao/OrderItemDao.java

public interface OrderItemDAO {
    public boolean saveOrderItem(OrderItem orderItem);
}

6.新建src/com/zzw/furns/dao/impl/OrderItemDaoImpl.java

public class OrderItemDAOImpl extends BasicDAO<OrderItem> implements OrderItemDAO {
    @Override
    public boolean saveOrderItem(OrderItem orderItem) {
        String sql = "INSERT INTO order_item(id, `name`, `count`, price, total_price, order_id) " +
                "VALUES(?, ?, ?, ?, ?, ?)";
        int update = update(sql, orderItem.getId(), orderItem.getName(), orderItem.getCount(),
                orderItem.getPrice(), orderItem.getTotalPrice(), orderItem.getOrderId());
        return update > 0;
    }
}

7.测试, 新建src/com/zzw/furns/test/OrderItemDAOTest.java

public class OrderItemDAOTest {
    private OrderItemDAO orderItemDAO = new OrderItemDAOImpl();
    @Test
    public void saveOrderItem() {
        OrderItem orderItem = new OrderItem(null, "小台灯", 10,
                new BigDecimal(25), new BigDecimal(10).multiply(new BigDecimal(25)), "9");
        boolean b = orderItemDAO.saveOrderItem(orderItem);
        System.out.println(b);
    }
}

8.新建src/com/zzw/furns/dao/OrderDao.java

public interface OrderDAO {
    //将传入的order对象 保存到数据库order表
    public boolean saveOrder(Order order);
}

9.新建src/com/zzw/furns/dao/impl/OrderDaoImpl.java

public class OrderDAOImpl extends BasicDAO<Order> implements OrderDAO {
    @Override
    public boolean saveOrder(Order order) {
        String sql = "INSERT INTO `order`(id, `create_time`, price, `count`, `status`, member_id) " +
                "VALUES(?, ?, ?, ?, ?, ?)";
        int update = update(sql, order.getId(), order.getCreateTime(), order.getPrice(), order.getCount(),
                order.getStatus(), order.getMemberId());
        return update > 0;
    }
}

10.测试, 新建src/com/zzw/furns/test/OrderDAOTest.java

public class OrderDAOTest {

    private OrderDAO orderDAO = new OrderDAOImpl();
    
    @Test
    public void saveOrder() {
        Order order = new Order(UUID.randomUUID().toString(), new Date(), new BigDecimal(22.00), 0, 123);
        boolean saveOrder = orderDAO.saveOrder(order);
        System.out.println(saveOrder);
    }
}

11.新建src/com/zzw/furns/service/OrderService.java

public interface OrderService {
    //1.生成订单
    //2.订单是根据cart来生成, cart对象在session. 通过web层, 传入saveOrder
    //3.订单和一个会员关联
    public String saveOrder(Cart cart, int memberId);
}

12.新建src/com/zzw/furns/service/impl/OrderServiceImpl.java

public class OrderServiceImpl implements OrderService {

    private OrderDAO orderDAO = new OrderDAOImpl();
    
    private OrderItemDAO orderItemDAO = new OrderItemDAOImpl();
    
    private FurnDAO furnDAO = new FurnDAOImpl();
    
    //在这里可以感受到javaee分层的好处. 在service层, 通过组合多个dao的方法,
    // 完成某个业务 慢慢体会好处
    
    @Override
    public String saveOrder(Cart cart, int memberId) {
        //将cart购物车的数据以order和orderItem的形式保存到DB中

        //因为生成订单会操作多张表, 因此会涉及到多表事务的问题, ThreadLocal+Mysql事务机制+过滤器

        //1.通过cart对象, 构建一个对应的order对象
        //  先生成一个UUID, 表示当前的订单号, UUID是唯一的
        String orderId = UUID.randomUUID().toString();//订单id
        Order order = new Order(orderId, new Date(), cart.getCartTotalPrice(), 0, memberId);
        //保存order到数据表
        orderDAO.saveOrder(order);//订单生成成功
        //通过cart对象, 遍历CartItem, 构建OrderItem对象, 并保存到对应的order_item表
        Map<Integer, CartItem> cartItems = cart.getItems();
        String orderItemId = "";
        for (CartItem cartItem : cartItems.values()) {
            //通过cartItem对象构建了orderItem对象
            OrderItem orderItem = new OrderItem(null, cartItem.getName(), cartItem.getCount(),
                    cartItem.getPrice(), cartItem.getTotalPrice(), orderId);
            //保存
            orderItemDAO.saveOrderItem(orderItem);

            //更新furn表  saleNum销量 - inventory库存
            //(1) 获取furn对象
            Furn furn = furnDAO.queryFurnById(cartItem.getId());
            //(2) 更新furn对象的 saleNum销量 - inventory库存
            furn.setInventory(furn.getInventory() - cartItem.getCount());
            furn.setSaleNum(furn.getSaleNum() + cartItem.getCount());
            //(3) 更新到数据表
            furnDAO.updateFurn(furn);
        }
        //清空购物车
        cart.clear();
        return orderId;
    }
}

13.测试src/com/zzw/furns/service/impl/OrderServiceTest.java

public class OrderServiceTest {
    private OrderService orderService = new OrderServiceImpl();

    @Test
    public void saveOrder() {
        //构建一个Cart对象
        Cart cart = new Cart();
        cart.addItem(new CartItem(1, "书桌", 1, new BigDecimal(12), new BigDecimal(12)));
        cart.addItem(new CartItem(2, "电脑", 2, new BigDecimal(12), new BigDecimal(24)));
        cart.addItem(new CartItem(3, "鼠标", 3, new BigDecimal(12), new BigDecimal(36)));

        String ordId = orderService.saveOrder(cart, 12);
        System.out.println("ordId = " + ordId);
    }
}

14.新建src/com/zzw/furns/web/OrderServlet.java

public class OrderServlet extends BasicServlet {
    //定义属性
    private OrderService orderService = new OrderServiceImpl();

    /**
     * 生成订单
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    protected void saveOrder(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        //获取购物车
        Cart cart = (Cart) session.getAttribute("cart");

        //如果cart为空, 说明会员没有购买任何家居, 转发到首页
		//这里需要补充逻辑: 购物车在session里, 但没有家居数据
        if (cart == null || cart.isEmpty()) {
            //重定向, 请求转发后面的代码会继续执行
            response.sendRedirect(request.getContextPath());
            return;
        }

        //获取到登陆的member对象
        Member member = (Member) session.getAttribute("member");
        if (member == null) {//说明用户没有登录, 转发到登陆页面
            //重定向到登陆页面
            request.getRequestDispatcher("/views/member/login.jsp")
                    .forward(request, response);
            return;//直接返回
        }

        //可以生成订单
        String orderId = orderService.saveOrder(cart, member.getId());//订单, 订单明细已生成
        session.setAttribute("orderId", orderId);//订单id
        //使用重定向放入到checkout.jsp
        response.sendRedirect(request.getContextPath() + "/views/order/checkout.jsp");
    }
}

15.新建web/views/order/checkout.jsp

16.测试src/com/zzw/furns/test/CartTest.java, 防止生成空订单

@Test
public void isEmpty() {
    Map<Object, Object> map = new HashMap<>();
    map.put("k", "v");
    map.clear();
    System.out.println(map == null);//false
    System.out.println(map.size());//0
}

17.查看HashMap源码

public void clear() {
    Node<K,V>[] tab;
    modCount++;
    if ((tab = table) != null && size > 0) {
    	//clear之后, size置为0
        size = 0;
        for (int i = 0; i < tab.length; ++i)
            tab[i] = null;
    }
}

18.修改web/views/cart/cart.jsp

<div class="cart-shiping-update">
    <a href="orderServlet?action=saveOrder">购 物 车 结 账</a>
</div>

<a class="active" href="index.jsp">
    <h4>订单已结算, 订单号-${sessionScope.orderId}</h4>
</a>

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

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

相关文章

比较顺序3s1,3s2,4s1之间的关系

(A,B)---6*30*2---(0,1)(1,0) 分类A和B&#xff0c;让B全是0。当收敛误差为7e-4&#xff0c;收敛199次取迭代次数平均值&#xff0c;3s1为 3s2为 4s1为 3s1&#xff0c;3s2&#xff0c;4s1这3个顺序之间是否有什么联系 &#xff0c; 因为4s1可以按照结构加法 变换成与4s1内在…

Linux相关概念和重要知识点(2)(用户、文件和目录、inode、权限)

1.root和普通用户 在Windows里面&#xff0c;管理员Administrator是所有用户里面权限最高的&#xff0c;很多文件都会提示请使用管理员打开等。但在整个Windows系统中&#xff0c;管理员的权限并不是最大的&#xff0c;System优先级更高&#xff0c;因此我们系统中的某些文件是…

谈谈ES搜索引擎

一 ES的定义 ES 它的全称是 Elasticsearch&#xff0c;是一个建立在全文搜索引擎库Lucene基础上的一个开源搜索和分析引擎。ES 它本身具备分布式存储&#xff0c;检索速度快的特性&#xff0c;所以我们经常用它来实现全文检索功能。目前在 Elastic 官网对 ES 的定义&#xff0c…

模拟实现vector中的常见接口

insert void insert(iterator pos, const T& x) {if (_finish _endofstorage){int n pos - _start;size_t newcapacity capacity() 0 ? 2 : capacity() * 2;reserve(newcapacity);pos _start n;//防止迭代器失效}int end _finish-1;while (end > pos){*(end 1…

PMBOK® 第六版 规划进度管理

目录 读后感—PMBOK第六版 目录 规划进度管理主要关注为整个项目期间的进度管理提供指南和方向。以下是两个案例&#xff0c;展示了进度管理中的复杂性和潜在的冲突&#xff1a; 案例一&#xff1a;近期&#xff0c;一个长期合作的客户因政策要求&#xff0c;急需我们为多家医…

SQL的增删改查CRUD练习知识点(day27)

1 学习目标 重点掌握插入单条记录的语法了解全表插入记录的语法重点掌握修改记录的语法重点掌握删除记录的语法重点掌握主键约束、外键约束了解检查约束、非空约束、唯一约束 2 数据类型 MySQL支持多种数据类型&#xff0c;大致可以分类三类&#xff1a;数值、日期和字符串。…

【JavaEE初阶】多线程(3)

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 线程状态 线程安全 代码示例 解释 总结原因 解决方案-->加锁 t1和t2都加锁 且 同一个锁对象 t1和t2中只有一个加锁了 t1和t2都加锁,但锁对象不同 加锁 与线程等待…

我给孩子请了个AI老师,省掉了1999元的报名费

大家好&#xff0c;我是凡人。 最近老婆想给儿子在线报个书法班&#xff0c;要价1999元&#xff0c;本来是个好事情&#xff0c;但一向勤俭持家的我&#xff0c;怎能让她花这个冤枉钱&#xff0c;经过我三七二十一个小时的上网&#xff0c;还真让我找出一套利用AI学习的万能命…

图片无损放大编辑PhotoZoom Pro 9.0.4多版本软件2024年最新安装包下载含安装教程

PhotoZoom Pro 9.0.4是一款非常流行的图像放大软件&#xff0c;它可以让你将低分辨率的图像放大到高分辨率的尺寸&#xff0c;同时保持高质量的图像细节和清晰度。 PhotoZoom Pro 9.0.4采用了一种称为S-Spline技术的算法&#xff0c;这是一种能够保持图像细节的高级插值算法。…

Web3 详解

1. 使用 Web3 库 Web3 是一个 JavaScript 库&#xff0c;可用于通过 RPC 通信与以太坊节点通信。 Web3 的工作方式是&#xff0c;公开已通过 RPC 启用的方法&#xff0c;这允许开发利用 Web3 库的用户界面&#xff0c;以便与部署在区块链上的合约进行交互。 一旦 Geth JavaScri…

25届计算机专业选题推荐-基于python的线上拍卖会管理系统【python-爬虫-大数据定制】

&#x1f496;&#x1f525;作者主页&#xff1a;毕设木哥 精彩专栏推荐订阅&#xff1a;在 下方专栏&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; 实战项目 文章目录 实战项目 一、基于python的线上拍卖会管理…

Window下编译OpenJDK17

本文详细介绍Window下如何编译OpenJDK17&#xff0c;包含源码路径&#xff0c;各工具下载地址&#xff0c;严格按照文章中的步骤来操作&#xff0c;你将获得一个由自己亲手编译出的jdk。 一、下载OpenJDK17源码 下载地址&#xff1a;GitHub - openjdk/jdk at jdk-1735 说明&a…

碰撞检测 | 详解矩形AABB与OBB碰撞检测算法(附ROS C++可视化)

引言 在复杂的人工智能系统和机器人应用中,碰撞检测(Collision Detection)作为一项基础技术,扮演着至关重要的角色。无论是在自动驾驶车辆中防止车祸的发生,还是在机器人导航中避免障碍物,碰撞检测的精度和效率都直接决定了系统的可靠性和安全性。在游戏开发、虚拟现实、…

USART—串口通讯

USART—串口通讯 大纲 串口通讯协议简介STM32 的 USART 简介USART 功能框图USART 初始化结构体详解 具体案例 串口通讯协议简介 物理层 串口通讯的物理层有很多标准及变种&#xff0c;我们主要讲解 RS-232 标准&#xff0c;RS-232 标准主要规定了信号的用途、通讯接口以及…

SpringCache之本地缓存

针对不同的缓存技术&#xff0c;需要实现不同的cacheManager&#xff0c;Spring定义了如下的cacheManger实现。 CacheManger 描述 SimpleCacheManager 使用简单的Collection来存储缓存&#xff0c;主要用于测试 ConcurrentMapCacheManager 使用ConcurrentMap作为缓存技术&…

spring揭秘20-spring事务02-编程式事务与声明式事务管理

文章目录 【README】【1】编程式事务管理【1.1】使用PlatformTransactionManager进行编程式事务管理【1.2】使用TransactionTemplate进行编程式事务管理【1.3】基于Savepoint的嵌套事务 【2】声明式事务管理【2.1】基于xml的声明式事务【2.1.1】使用ProxyFactory&#xff08;Pr…

【基础篇】应届毕业生必备:机器学习面试题指南【1】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发…

【软件工程】软件开发模型

三、瀑布模型 四、几种软件开发模型的主要特点 题目 判断题 选择题 小结

房贷计算及比较

本博客主要介绍&#xff1a; 1. 等额本金计算公式 2. 等额本息计算公式 3. 对比两种还款方式 4. 本示例:贷款金额为35万&#xff0c; 期限12年&#xff0c;年利率4.9% 等额本金计算 import matplotlib.pyplot as plt import matplotlib matplotlib.rcParams[font.sans-s…

day1 QT

作业 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置窗口大小this->resize(1025,533);//固定窗口大小this->setFixedSize(1025,533);//设置窗口背景色,设置弧度//this->setStyleSheet("background-image:url(E:/…