【J2EE】模仿天猫商城(前台篇)-02购物

围绕购物流程最重要的两个表是OrderItem 和 Order表

Order表 

关于OrderItem的业务行为
1. 立即购买 —— 新增 OrderItem
2. 加入购物车 —— 新增 OrderItem
3. 查看购物车 —— 显示未和Order关联的OrderItem
4. 选中购物车中的商品 —— 选中OrderItem
5. 结算页面 —— 显示选中的OrderItem

6. 生成订单 —— 新增Order
7 .付款 —— 修改Order状态
8. 我的订单 —— 显示Order
9. 确认收货 —— 修改Order状态

点击进入一个产品的详情页 ,如图

点击立即购买按钮

那么点击购买都做了什么事情呢? 会在OrderItem表里插入一条数据,这条数据会表示:
1. pid =844 购买的商品id
2. oid = -1, 这个订单项还没有生成对应的订单,即还在购物车中
3. uid= 3,用户的id是3
4. number=1, 购买了1件产品

如果没有登录的话,那么点击立即购买之前会弹出一个模态登录窗口

 具体代码

imgAndInfo.jsp中的一段js代码

$(".buyLink").click(function(){
    	//检查是否登录
        var page = "forecheckLogin";
        $.get(
                page,
                function(result){
                	//登录了,则跳转到购买链接
                    if("success"==result){
                        var num = $(".productNumberSetting").val();
                        location.href= $(".buyLink").attr("href")+"&num="+num;
                    }
                	//否则,弹出登录窗口
                    else{
                        $("#loginModal").modal('show');                    
                    }
                }
        );     
        return false;
    });

上面forecheckLogin是调用了ForeServlet中的checkLogin()方法

public String checkLogin(HttpServletRequest request, HttpServletResponse response, Page page) {
        User user =(User) request.getSession().getAttribute("user");
        if(null!=user)
            return "%success";
        return "%fail";
    }

在模态登录窗口中输入账号密码后,使用jQuery的ajax来登录,具体代码如下

$("button.loginSubmitButton").click(function(){
        var name = $("#name").val();
        var password = $("#password").val();
         
        if(0==name.length||0==password.length){
            $("span.errorMessage").html("请输入账号密码");
            $("div.loginErrorMessageDiv").show();          
            return false;
        }
         
        var page = "foreloginAjax";
        $.get(
                page,
                {"name":name,"password":password},
                function(result){
                    if("success"==result){
                        location.reload();
                    }
                    else{
                        $("span.errorMessage").html("账号密码错误");
                        $("div.loginErrorMessageDiv").show();                      
                    }
                }
        );         
         
        return true;
    });

同理,当我们点击加入购物车的时候,也会弹出登录窗口,这里不再写了。

接着当我们输入账号密码登录之后,我们再点击立即购买,看这段“立即购买”按钮的代码

href="forebuyone?pid=${p.id}带着当前产品的id,同时再看上面imgAndInfo.jsp中的js代码 

这里意思如果是登录了,则获取数量,并且跳转到/forebuyone同时带着p.id和num,那么根据上一节01的内容,这里其实就去调用ForeServlet中的buyone()方法,并且带着参数p.id和num。下面是buyone方法代码

public String buyone(HttpServletRequest request, HttpServletResponse response, Page page) {
    int pid = Integer.parseInt(request.getParameter("pid"));
    int num = Integer.parseInt(request.getParameter("num"));
    Product p = productDAO.get(pid);
    int oiid = 0;
     
    User user =(User) request.getSession().getAttribute("user");
    boolean found = false;
    List<OrderItem> ois = orderItemDAO.listByUser(user.getId());
    for (OrderItem oi : ois) {
        if(oi.getProduct().getId()==p.getId()){
            oi.setNumber(oi.getNumber()+num);
            orderItemDAO.update(oi);
            found = true;
            oiid = oi.getId();
            break;
        }
    }      
 
    if(!found){
        OrderItem oi = new OrderItem();
        oi.setUser(user);
        oi.setNumber(num);
        oi.setProduct(p);
        orderItemDAO.add(oi);
        oiid = oi.getId();
    }
    return "@forebuy?oiid="+oiid;
}

1. 获取参数pid
2. 获取参数num
3. 根据pid获取产品对象p
4. 从session中获取用户对象user

接下来就是新增订单项OrderItem, 新增订单项要考虑两个情况
a. 如果已经存在这个产品对应的OrderItem,并且还没有生成订单,即还在购物车中。 那么就应该在对应的OrderItem基础上,调整数量
a.1 基于用户对象user,查询没有生成订单的订单项集合
a.2 遍历这个集合
a.3 如果产品是一样的话,就进行数量追加
a.4 获取这个订单项的 id

b. 如果不存在对应的OrderItem,那么就新增一个订单项OrderItem
b.1 生成新的订单项
b.2 设置数量,用户和产品
b.3 插入到数据库
b.4 获取这个订单项的 id

注:这里是根据用户id查询没有生成订单(即购物车中)的订单项,其中sql语句有个oid= -1 当OrderItem表中的oid字段等于 -1,即表示没有对应的订单;当我们插入订单项到orderItem中时,orderItem的add方法会设置oid为-1,同时插入成功后还会返回一个id,即oiid。

    public List<OrderItem> listByUser(int uid) {
        return listByUser(uid, 0, Short.MAX_VALUE);
    }
  
    public List<OrderItem> listByUser(int uid, int start, int count) {
        List<OrderItem> beans = new ArrayList<OrderItem>();
  
        String sql = "select * from OrderItem where uid = ? and oid=-1 order by id desc limit ?,? ";
  
        try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
  
            ps.setInt(1, uid);
            ps.setInt(2, start);
            ps.setInt(3, count);
  
            ResultSet rs = ps.executeQuery();
  
            while (rs.next()) {
                OrderItem bean = new OrderItem();
                int id = rs.getInt(1);
 
                int pid = rs.getInt("pid");
                int oid = rs.getInt("oid");
                int number = rs.getInt("number");
                 
                Product product = new ProductDAO().get(pid);
                if(-1!=oid){
                    Order order= new OrderDAO().get(oid);
                    bean.setOrder(order);                  
                }
 
                User user = new UserDAO().get(uid);
                bean.setProduct(product);
 
                bean.setUser(user);
                bean.setNumber(number);
                bean.setId(id);               
                beans.add(bean);
            }
        } catch (SQLException e) {
  
            e.printStackTrace();
        }
        return beans;
    }
public void add(OrderItem bean) {
 
        String sql = "insert into OrderItem values(null,?,?,?,?)";
        try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
  
            ps.setInt(1, bean.getProduct().getId());
             
            //订单项在创建的时候,是没有订单信息的,故设置oid为-1
            if(null==bean.getOrder())
                ps.setInt(2, -1);
            else
                ps.setInt(2, bean.getOrder().getId()); 
             
            ps.setInt(3, bean.getUser().getId());
            ps.setInt(4, bean.getNumber());
            ps.execute();
  
            ResultSet rs = ps.getGeneratedKeys();
            if (rs.next()) {
                int id = rs.getInt(1);
                bean.setId(id);
            }
        } catch (SQLException e) {
  
            e.printStackTrace();
        }
    }


最后, 基于这个订单项id客户端跳转到结算页面/forebuy

结算界面: 

通过地址栏上的地址

可以发现跳转到/forebuy其实就是进行了服务器端的跳转,使得ForeServlet.buy()被调用了

buy方法代码

public String buy(HttpServletRequest request, HttpServletResponse response, Page page){
    String[] oiids=request.getParameterValues("oiid");
    List<OrderItem> ois = new ArrayList<>();
    float total = 0;
 
    for (String strid : oiids) {
        int oiid = Integer.parseInt(strid);
        OrderItem oi= orderItemDAO.get(oiid);
        total +=oi.getProduct().getPromotePrice()*oi.getNumber();
        ois.add(oi);
    }
     
    request.getSession().setAttribute("ois", ois);
    request.setAttribute("total", total);
    return "buy.jsp";
}  

1. 通过getParameterValues获取参数oiid
为什么这里要用getParameterValues试图获取多个oiid,而不是getParameter仅仅获取一个oiid? 因为结算页面还需要显示在购物车中选中的多条OrderItem数据,所以为了兼容从购物车页面跳转过来的需求,要用getParameterValues获取多个oiid
2. 准备一个泛型是OrderItem的集合ois
3. 根据前面步骤获取的oiids,从数据库中取出OrderItem对象,并放入ois集合中
4. 累计这些ois的价格总数,赋值在total上
5. 把订单项集合放在session的属性 "ois" 上
6. 把总价格放在 request的属性 "total" 上
7. 服务端跳转到buy.jsp

在buy.jsp中,除了遍历出订单项集合ois和显示总价外,还需设置表单用于填写用户信息,当用户填写好点击提交按钮时,将跳转到forecreateOrder,实际上也就是调用了foreServlet.createOrder,这里是buy.jsp的代码片段。

 提交订单访问路径 /forecreateOrder, 导致ForeServlet.createOrder 方法被调用
1. 从session中获取user对象
2. 获取地址,邮编,收货人,用户留言等信息
3. 根据当前时间加上一个4位随机数生成订单号
4. 根据上述参数,创建订单对象
5. 把订单状态设置为等待支付
6. 加入到数据库
7. 从session中获取订单项集合 ( 在ForeServlet.buy中,订单项集合被放到了session中 )
8. 遍历订单项集合,设置每个订单项的order,并更新到数据库
9. 统计本次订单的总金额
10. 客户端跳转到确认支付页forealipay,并带上订单id和总金额

public String createOrder(HttpServletRequest request, HttpServletResponse response, Page page){
    User user =(User) request.getSession().getAttribute("user");
     
    List<OrderItem> ois= (List<OrderItem>) request.getSession().getAttribute("ois");
    if(ois.isEmpty())
        return "@login.jsp";
 
    String address = request.getParameter("address");
    String post = request.getParameter("post");
    String receiver = request.getParameter("receiver");
    String mobile = request.getParameter("mobile");
    String userMessage = request.getParameter("userMessage");
     
    Order order = new Order();
    String orderCode = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) +RandomUtils.nextInt(10000);
 
    order.setOrderCode(orderCode);
    order.setAddress(address);
    order.setPost(post);
    order.setReceiver(receiver);
    order.setMobile(mobile);
    order.setUserMessage(userMessage);
    order.setCreateDate(new Date());
    order.setUser(user);
    order.setStatus(OrderDAO.waitPay);
 
    orderDAO.add(order);
    float total =0;
    for (OrderItem oi: ois) {
        oi.setOrder(order);
        orderItemDAO.update(oi);
        total+=oi.getProduct().getPromotePrice()*oi.getNumber();
    }
     
    return "@forealipay?oid="+order.getId() +"&total="+total;
}

 在上一步客户端跳转到路径/forealipay方法,导致ForeServlet.alipay()方法被调用。 alipay()没做什么事情,就是服务端跳转到了alipay.jsp页面。alipay.jsp也是包含了header.jsp,top.jsp,footer.jsp等公共页面,其中还有一个确认支付业务页面alipayPage.jsp,显示总金额,并且让确认支付按钮跳转到页面 /forepayed页面,并带上oid和金额

 在上一步确认访问按钮提交数据到/forepayed,导致ForeServlet.payed方法被调用
1.1 获取参数oid
1.2 根据oid获取到订单对象order
1.3 修改订单对象的状态和支付时间
1.4 更新这个订单对象到数据库
1.5 把这个订单对象放在request的属性"o"上
1.6 服务端跳转到payed.jsp

public String payed(HttpServletRequest request, HttpServletResponse response, Page page) {
    int oid = Integer.parseInt(request.getParameter("oid"));
    Order order = orderDAO.get(oid);
    order.setStatus(OrderDAO.waitDelivery);
    order.setPayDate(new Date());
    new OrderDAO().update(order);
    request.setAttribute("o", order);
    return "payed.jsp";    
}  

payed.jsp是支付成功业务页面 ,其中主要信息由payedPage.jsp显示

其中这里可以点击 查看交易详情,跳转到个人订单页面

 

/forebought导致ForeServlet.bought()方法被调用
1. 通过session获取用户user
2. 查询user所有的状态不是"delete" 的订单集合os
3. 为这些订单填充订单项
4. 把os放在request的属性"os"上
5. 服务端跳转到bought.jsp

public String bought(HttpServletRequest request, HttpServletResponse response, Page page) {
    User user =(User) request.getSession().getAttribute("user");
    List<Order> os= orderDAO.list(user.getId(),OrderDAO.delete);
     
    orderItemDAO.fill(os);
     
    request.setAttribute("os", os);
     
    return "bought.jsp";       
}

 到这里,一个购物的基本流程就走完了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值