显示登录的用户信息

用户登录成功后跳转到登录成功页面,需要显示用户名信息。若用户继续跳转到订单页面,也需要显示用户名信息

此时就不能使用Request域保存数据,因为它只在一次请求中有效,所以使用作用范围比它稍大的session域,这也正是session会话的作用,即保存用户登录后的信息

UserServlet.java

18-书城项目(第六七阶段)_验证码

login_success_menu.jsp

18-书城项目(第六七阶段)_验证码_02

用户点击返回,会跳转到首页,此时首页要显示的也是用户登录成功后的信息

client/index.jsp

18-书城项目(第六七阶段)_java_03

用户未登录

18-书城项目(第六七阶段)_表单_04

用户登录成功

18-书城项目(第六七阶段)_表单_05

返回首页

18-书城项目(第六七阶段)_验证码_06

注销登录

用户点击注销后需要做两件事,销毁session中的用户登录信息(或是销毁session),重定向到首页或登录页面

login_success_menu.jsp

18-书城项目(第六七阶段)_表单_07

client/index.jsp

18-书城项目(第六七阶段)_表单_08

UserServlet.java

18-书城项目(第六七阶段)_java_09

表单重复提交的三种常见情况

1,提交完表单,服务器使用请求转发进行页面跳转,若此时用户按下f5刷新页面,则又会发起浏览器记录的最后一次请求,造成表单重复提交。解决方法是将请求转发改为重定向来进行跳转

新建临时动态web工程tmp

regist.jsp

18-书城项目(第六七阶段)_验证码_10

RegistServlet.java

18-书城项目(第六七阶段)_验证码_11

web.xml

18-书城项目(第六七阶段)_java_12

第一行输出是点击提交后的结果,之后每次按下f5都会打印一条。因为是请求转发,所以第一次点击提交至转发到ok.jsp的整个过程只是一次请求,每次f5浏览器都会发起这次请求,就出现了表单重复提交

18-书城项目(第六七阶段)_表单_13

将请求转发改为重定向,重定向是一次新的请求,浏览器记录下最后的这次请求,之后f5发起的是重定向的这个请求,就不会出现表单重复提交

18-书城项目(第六七阶段)_验证码_14

2,用户正常提交给服务器,但由于网络延迟等原因导致未收到服务器响应,此时用户认为提交失败,就会多点几次提交,也会造成表单重复提交

18-书城项目(第六七阶段)_java_15

用户提交后没有反应,多次点击提交造成表单重复提交

18-书城项目(第六七阶段)_java_16

3,用户正常提交给服务器,没有网络延迟,但提交完成后用户点击回退,重新提交,也会造成表单重复提交

18-书城项目(第六七阶段)_验证码_17

用户提交完成后多次点击回退并重新提交,也会造成表单重复提交

18-书城项目(第六七阶段)_验证码_18

18-书城项目(第六七阶段)_表单_19

验证码底层原理

上述表单重复提交的后两种情况可以使用验证码解决

18-书城项目(第六七阶段)_验证码_20

谷歌验证码的使用

谷歌验证码kaptcha使用步骤:

1,导入谷歌验证码的jar包(Add as Library...)

18-书城项目(第六七阶段)_验证码_21

18-书城项目(第六七阶段)_验证码_22

18-书城项目(第六七阶段)_表单_23

2,在web.xml中配置用于生成验证码的Servlet程序,该Servlet定义在导入的jar包中。访问/kaptcha.jpg会生成验证码图片并保存到session域中

18-书城项目(第六七阶段)_表单_24

3,在表单中使用img标签显示验证码图片,regist.jsp

18-书城项目(第六七阶段)_验证码_25

4,服务器获取谷歌生成的验证码,比较客户端发送过来的验证码,RegistServlet.java

18-书城项目(第六七阶段)_验证码_26

用户访问regist.jsp,img标签访问/kaptcha.jsp得到验证码图片,用户输入后点击登录。首先获取生成验证码的Servlet程序在session域中保存的验证码,然后删除域中的验证码,比较用户填写的验证码和生成的验证码是否一致,一致则显示登录成功。若此时用户点击回退并重新登录,这是session域中的验证码已被删除,就不会显示登录成功并提示用户请勿重复提交表单,解决了表单重复提交的问题


将谷歌验证码功能加入书城

在book工程中导入jar包

18-书城项目(第六七阶段)_表单_27

web.xml

18-书城项目(第六七阶段)_验证码_28

regist.jsp

18-书城项目(第六七阶段)_验证码_29

UserServlet.java

18-书城项目(第六七阶段)_表单_30


验证码的切换

regist.jsp

18-书城项目(第六七阶段)_java_31

18-书城项目(第六七阶段)_验证码_32

但是还有一个问题需要注意,当使用火狐或IE浏览器刷新验证码时,第一次点击时图片会改变,之后点击图片不变。这是缓存的原因,第一次点击后服务器返回验证码图片,浏览器将图片以请求地址的资源名&参数为名缓存到内存或硬盘中,以上面为例,缓存图片为kaptcha.jsp,之后每次点击的请求地址都不变,浏览器认为请求的资源一样,就直接返回缓存的数据

解决方法就是给每次请求都加上不一样的参数

18-书城项目(第六七阶段)_表单_33

购物车模块的分析

18-书城项目(第六七阶段)_表单_34

购物车模型的创建

购物车商品项类

package com.atguigu.pojo;

import java.math.BigDecimal;

public class CartItem {

private Integer id;
private String name;
private Integer count;
private BigDecimal price;
private BigDecimal totalPrice;

public CartItem() {
}

public CartItem(Integer id, String name, Integer count, BigDecimal price, BigDecimal totalPrice) {
this.id = id;
this.name = name;
this.count = count;
this.price = price;
this.totalPrice = totalPrice;
}

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 Integer getCount() {
return count;
}

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

public BigDecimal getPrice() {
return price;
}

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

public BigDecimal getTotalPrice() {
return totalPrice;
}

public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}

@Override
public String toString() {
return "CartItem{" +
"id=" + id +
", name='" + name + '\'' +
", count=" + count +
", price=" + price +
", totalPrice=" + totalPrice +
'}';
}
}

购物车类

package com.atguigu.pojo;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

public class Cart {

private Integer totalCount;
private BigDecimal totalPrice;
private List<CartItem> items = new ArrayList<CartItem>();

public Cart() {
}

public Cart(Integer totalCount, BigDecimal totalPrice, List<CartItem> items) {
this.totalCount = totalCount;
this.totalPrice = totalPrice;
this.items = items;
}

public Integer getTotalCount() {
return totalCount;
}

public void setTotalCount(Integer totalCount) {
this.totalCount = totalCount;
}

public BigDecimal getTotalPrice() {
return totalPrice;
}

public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}

public List<CartItem> getItems() {
return items;
}

public void setItems(List<CartItem> items) {
this.items = items;
}

@Override
public String toString() {
return "Cart{" +
"totalCount=" + totalCount +
", totalPrice=" + totalPrice +
", items=" + items +
'}';
}
}

购物车功能方法的实现和测试

修改存储商品项的集合为Map,便于后续方法操作,items的get()和set()返回值类型也要修改。删除totalCount和totalPrice两个属性,改成在需要获取这两个属性时通过遍历Map集合获取

修改后的Cart.java

package com.atguigu.pojo;

import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;

public class Cart {

// key代表商品编号,value为商品信息
private Map<Integer, CartItem> items = new LinkedHashMap<Integer, CartItem>();

public Integer getTotalCount() {
Integer totalCount = 0;
for (Map.Entry<Integer, CartItem> entry : items.entrySet()) {
totalCount += entry.getValue().getCount();
}
return totalCount;
}

public BigDecimal getTotalPrice() {
BigDecimal totalPrice = new BigDecimal(0);
for (Map.Entry<Integer, CartItem> entry : items.entrySet()) {
totalPrice = totalPrice.add(entry.getValue().getTotalPrice());
}
return totalPrice;
}

public Map<Integer, CartItem> getItems() {
return items;
}

public void setItems(Map<Integer, CartItem> items) {
this.items = items;
}

@Override
public String toString() {
return "Cart{" +
"totalCount=" + getTotalCount() +
", totalPrice=" + getTotalPrice() +
", items=" + items +
'}';
}

/**
* 添加商品项
* @param cartItem
*/
public void addItem(CartItem cartItem) {
// 先判断购物车中是否已经添加过该商品,若已有则累加数量、更新总金额,若没有则添加进集合
CartItem item = items.get(cartItem.getId());
if (item == null) {
items.put(cartItem.getId(), cartItem);
} else {
item.setCount(item.getCount() + 1);
// multiply()是BigDecimal类型的乘法
item.setTotalPrice(item.getPrice().multiply(new BigDecimal(item.getCount())));
}
}

/**
* 删除商品项
* @param id
*/
public void deleteItem(Integer id) {
items.remove(id);
}

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

/**
* 修改商品数量
* @param id
* @param count
*/
public void updateCount(Integer id, Integer count) {
// 先判断购物车中是否已有此商品,有就更新商品数量、总金额
CartItem cartItem = items.get(id);
if (cartItem != null) {
cartItem.setCount(count);
cartItem.setTotalPrice(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())));
}
}
}

Ctrl+shift+t生成测试方法

18-书城项目(第六七阶段)_java_35

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

@Test
public void deleteItem() {
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)));
cart.deleteItem(1);
System.out.println(cart);
}

@Test
public void clear() {
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)));
cart.clear();
System.out.println(cart);
}

@Test
public void updateCount() {
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)));
cart.updateCount(1, 10);
System.out.println(cart);
}

添加商品到购物车功能的实现

client/index.jsp

18-书城项目(第六七阶段)_验证码_36

18-书城项目(第六七阶段)_验证码_37

package com.atguigu.web;

import com.atguigu.pojo.Book;
import com.atguigu.pojo.Cart;
import com.atguigu.pojo.CartItem;
import com.atguigu.service.BookService;
import com.atguigu.service.impl.BookServiceImpl;
import com.atguigu.utils.WebUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CartServlet extends BaseServlet {

private BookService bookService = new BookServiceImpl();

protected void addItem(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求中的参数商品编号
int id = WebUtils.parseInt(req.getParameter("id"), 0);
// 查询得到对应编号的图书信息
Book book = bookService.queryBookById(id);
// 将图书信息转换为CartItem对象
CartItem cartItem = new CartItem(book.getId(), book.getName(), 1, book.getPrice(), book.getPrice());
// 在session域中获取购物车对象,若没有就创建,保证只有一个购物车对象
Cart cart = (Cart) req.getSession().getAttribute("cart");
if (cart == null) {
cart = new Cart();
req.getSession().setAttribute("cart", cart);
}
// 将商品项进入购物车
cart.addItem(cartItem);
// 浏览器发起请求时会通过请求头Referer将地址栏中的地址发送给服务器
// 重定向回发起请求的页面,即在哪个页面执行的加入购物车操作就跳回到哪个页面
resp.sendRedirect(req.getHeader(("Referer")));
}
}

web.xml

18-书城项目(第六七阶段)_验证码_38


购物车的展示

cart.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>购物车</title>
<%-- 静态包含,base标签、css样式、jQuery文件 --%>
<%@ include file="/pages/common/head.jsp"%>
</head>
<body>

<div id="header">
<img class="logo_img" alt="" src="static/img/logo.gif" >
<span class="wel_word">购物车</span>
<%-- 静态包含,登录成功后的菜单 --%>
<%@ include file="/pages/common/login_success_menu.jsp"%>
</div>

<div id="main">

<table>
<tr>
<td>商品名称</td>
<td>数量</td>
<td>单价</td>
<td>金额</td>
<td>操作</td>
</tr>

<c:if test="${ empty sessionScope.cart.items }">
<tr>
<td colspan="5"><a href="index.jsp">当前购物车为空!跳转至首页</a></td>
</tr>
</c:if>

<c:if test="${ not empty sessionScope.cart.items }">
<c:forEach items="${ sessionScope.cart.items }" var="entry">
<tr>
<td>${ entry.value.name }</td>
<td>${ entry.value.count }</td>
<td>${ entry.value.price }</td>
<td>${ entry.value.totalPrice }</td>
<td><a href="#">删除</a></td>
</tr>
</c:forEach>
</c:if>

</table>

<%-- 购物车不为空时,输出下面的内容 --%>
<c:if test="${ not empty sessionScope.cart.items }">
<div class="cart_info">
<span class="cart_span">购物车中共有<span class="b_count">${ sessionScope.cart.totalCount }</span>件商品</span>
<span class="cart_span">总金额<span class="b_price">${ sessionScope.cart.totalPrice }</span></span>
<span class="cart_span"><a href="#">清空购物车</a></span>
<span class="cart_span"><a href="pages/cart/checkout.jsp">去结账</a></span>
</div>
</c:if>

</div>

<%-- 静态包含页脚内容 --%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>

删除购物车中的商品项

cart.jsp

18-书城项目(第六七阶段)_java_39

18-书城项目(第六七阶段)_表单_40

CartServlet.java

18-书城项目(第六七阶段)_验证码_41

清空购物车的实现

cart.jsp

18-书城项目(第六七阶段)_java_42

18-书城项目(第六七阶段)_验证码_43

cartServlet.java

18-书城项目(第六七阶段)_验证码_44

修改购物车商品数量

cart.jsp

18-书城项目(第六七阶段)_表单_45

18-书城项目(第六七阶段)_java_46

cartServlet.java

18-书城项目(第六七阶段)_验证码_47

首页购物车数据展示

client/index.jsp

18-书城项目(第六七阶段)_验证码_48

CartServlet.java的addItem()

18-书城项目(第六七阶段)_表单_49

订单模块的分析

18-书城项目(第六七阶段)_java_50

创建订单模型的数据库表

需要外键约束,即数据行中某列的值必须是指定表的指定列中存在的

CREATE TABLE t_order(
`order_id` VARCHAR(50) PRIMARY KEY,
`create_time` DATETIME,
`price` DECIMAL(11,2),
`status` INT,
`user_id` INT,
FOREIGN KEY(`user_id`) REFERENCES t_user(`id`)
);
CREATE TABLE t_order_item(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARBINARY(100),
`count` INT,
`price` DECIMAL(11,2),
`total_price` DECIMAL(11,2),
`order_id` VARCHAR(50),
FOREIGN KEY(`order_id`) REFERENCES t_order(`order_id`)
);

编写订单模块的两个数据模型Order和OrderItem

package com.atguigu.pojo;

import java.math.BigDecimal;
import java.util.Date;

public class Order {

private String orderId;
private Date createTime;
private BigDecimal price;
private Integer status = 0;
private Integer userId;

public Order() {
}

public Order(String orderId, Date createTime, BigDecimal price, Integer status, Integer userId) {
this.orderId = orderId;
this.createTime = createTime;
this.price = price;
this.status = status;
this.userId = userId;
}

public String getOrderId() {
return orderId;
}

public void setOrderId(String orderId) {
this.orderId = orderId;
}

public Date getCreateTime() {
return createTime;
}

public void setCreateTime(Date createTime) {
this.createTime = createTime;
}

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 getUserId() {
return userId;
}

public void setUserId(Integer userId) {
this.userId = userId;
}

@Override
public String toString() {
return "Order{" +
"orderId='" + orderId + '\'' +
", createTime=" + createTime +
", price=" + price +
", status=" + status +
", userId=" + userId +
'}';
}
}
package com.atguigu.pojo;

import java.math.BigDecimal;

public class OrderItem {

private Integer id;
private String name;
private Integer count;
private BigDecimal price;
private BigDecimal totalPrice;
private String orderId;

public OrderItem() {
}

public OrderItem(Integer id, String name, Integer count, BigDecimal price, BigDecimal totalPrice, String orderId) {
this.id = id;
this.name = name;
this.count = count;
this.price = price;
this.totalPrice = totalPrice;
this.orderId = orderId;
}

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 Integer getCount() {
return count;
}

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

public BigDecimal getPrice() {
return price;
}

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

public BigDecimal getTotalPrice() {
return totalPrice;
}

public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}

public String getOrderId() {
return orderId;
}

public void setOrderId(String orderId) {
this.orderId = orderId;
}

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

编写订单模块的Dao和测试

package com.atguigu.dao;

import com.atguigu.pojo.Order;

public interface OrderDao {

public int saveOrder(Order order);
}
package com.atguigu.dao;

import com.atguigu.pojo.OrderItem;

public interface OrderItemDao {

public int saveOrderItem(OrderItem orderItem);
}
package com.atguigu.dao.impl;

import com.atguigu.dao.OrderDao;
import com.atguigu.pojo.Order;

public class OrderDaoImpl extends BaseDao implements OrderDao {

@Override
public int saveOrder(Order order) {
String sql = "insert into t_order(`order_id`,`create_time`,`price`,`status`,`user_id`) values(?,?,?,?,?)";
return update(sql,order.getOrderId(),order.getCreateTime(),order.getPrice(),order.getStatus(),order.getUserId());
}
}
package com.atguigu.dao.impl;

import com.atguigu.dao.OrderItemDao;
import com.atguigu.pojo.OrderItem;

public class OrderItemDaoImpl extends BaseDao implements OrderItemDao {
@Override
public int saveOrderItem(OrderItem orderItem) {
String sql = "insert into t_order_item(`name`,`count`,`price`,`total_price`,`order_id`) values(?,?,?,?,?)";
update(sql,orderItem.getName(),orderItem.getCount(),orderItem.getPrice(),orderItem.getTotalPrice(),orderItem.getOrderId());
return 0;
}
}
package com.atguigu.test;

import com.atguigu.dao.OrderDao;
import com.atguigu.dao.impl.OrderDaoImpl;
import com.atguigu.pojo.Order;
import org.junit.Test;

import java.math.BigDecimal;
import java.util.Date;

public class OrderDaoTest {

@Test
public void saveOrder() {
OrderDao orderDao = new OrderDaoImpl();
orderDao.saveOrder(new Order("1234567890", new Date(), new BigDecimal(100), 0, 1));
}
}
package com.atguigu.test;

import com.atguigu.dao.OrderItemDao;
import com.atguigu.dao.impl.OrderItemDaoImpl;
import com.atguigu.pojo.OrderItem;
import org.junit.Test;

import java.math.BigDecimal;

public class OrderItemDaoTest {

@Test
public void saveOrderItem() {
OrderItemDao orderItemDao = new OrderItemDaoImpl();
orderItemDao.saveOrderItem(new OrderItem(null, "Java从入门到精通", 1, new BigDecimal(100), new BigDecimal(100), "1234567890"));
orderItemDao.saveOrderItem(new OrderItem(null, "JavaScript从入门到精通", 2, new BigDecimal(100), new BigDecimal(200), "1234567890"));
orderItemDao.saveOrderItem(new OrderItem(null, "c++从入门到精通", 1, new BigDecimal(100), new BigDecimal(100), "1234567890"));
}
}

18-书城项目(第六七阶段)_表单_51

18-书城项目(第六七阶段)_验证码_52

编写订单模块的Service和测试

package com.atguigu.service;

import com.atguigu.pojo.Cart;

public interface OrderService {

public String createOrder(Cart cart, Integer userId);
}
package com.atguigu.service.impl;

import com.atguigu.dao.OrderDao;
import com.atguigu.dao.OrderItemDao;
import com.atguigu.dao.impl.OrderDaoImpl;
import com.atguigu.dao.impl.OrderItemDaoImpl;
import com.atguigu.pojo.Cart;
import com.atguigu.pojo.CartItem;
import com.atguigu.pojo.Order;
import com.atguigu.pojo.OrderItem;
import com.atguigu.service.OrderService;

import java.util.Date;
import java.util.Map;

public class OrderServiceImpl implements OrderService {

private OrderDao orderDao = new OrderDaoImpl();
private OrderItemDao orderItemDao = new OrderItemDaoImpl();

@Override
public String createOrder(Cart cart, Integer userId) {
// 订单号要保证唯一,当有两个用户同时创建订单时,加上他们的userId来保证订单号唯一
String orderId = System.currentTimeMillis() + "" + userId;
Order order = new Order(orderId, new Date(), cart.getTotalPrice(), 0, userId);
orderDao.saveOrder(order);
// 遍历购物车中的每个商品项,转换为订单项后保存到数据库
for (Map.Entry<Integer, CartItem> entry : cart.getItems().entrySet()) {
CartItem cartItem = entry.getValue();
OrderItem orderItem = new OrderItem(null, cartItem.getName(), cartItem.getCount(), cartItem.getPrice(), cartItem.getTotalPrice(), orderId);
orderItemDao.saveOrderItem(orderItem);
}
// 点击结账后要清空购物车
cart.clear();
return orderId;
}
}
package com.atguigu.test;

import com.atguigu.pojo.Cart;
import com.atguigu.pojo.CartItem;
import com.atguigu.service.impl.OrderServiceImpl;
import org.junit.Test;

import java.math.BigDecimal;

import static org.junit.Assert.*;

public class OrderServiceTest {

@Test
public void createOrder() {
Cart cart = new Cart();
OrderServiceImpl orderService = new OrderServiceImpl();
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(orderService.createOrder(cart, 1));
}
}

18-书城项目(第六七阶段)_java_53

18-书城项目(第六七阶段)_验证码_54

结账功能实现,生成订单

cart.jsp

18-书城项目(第六七阶段)_java_55

OrderServlet.java

18-书城项目(第六七阶段)_java_56

web.xml

18-书城项目(第六七阶段)_表单_57

checkout.jsp

18-书城项目(第六七阶段)_java_58


解决生成订单的bug

OrderServlet.java

18-书城项目(第六七阶段)_java_59

checkout.jsp

18-书城项目(第六七阶段)_验证码_60

订单结账后首页显示的库存、销量要相应的改变

18-书城项目(第六七阶段)_验证码_61