zoukankan      html  css  js  c++  java
  • 购物车【JavaWeb小项目、简单版】

    前言

    为了巩固MVC的开发模式,下面就写一个购物车的小案例..

    ①构建开发环境

    导入需要用到的开发包

    建立程序开发包


    ②设计实体

    书籍实体

    
    	public class Book {
    	
    	    private String id;
    	    private String name;
    	    private String author;
    	    private String description;
    	    private double price;
    	
    	    public Book() {
    	    }
    	
    	    public Book(String id, String name, String author, String description, double price) {
    	        this.id = id;
    	        this.name = name;
    	        this.author = author;
    	        this.description = description;
    	        this.price = price;
    	    }
    	
    		//...各种setter和getter
    	}
    
    

    购物车与购物项实体

    可能我们会这样设计购物车

    
    	/*该类代表的是购物车*/
    	public class Cart {
    	
    	    //关键字是书籍的id,值是书
    	    private Map<String, Book> bookMap = new LinkedHashMap<>();
    	
    	
    	}
    
    

    上面的做法是不合适的,试想一下:如果我要购买两本相同的书,购物车的页面上就出现了两本书,而不是书2。买三本相同的书就在购物页面上出现三本书,而不是书3.

    因此,Map集合的值不能是Book对象,那我们怎么才能解决上面所说的问题呢?我们最常用的就是,再写一个实体CartItem(代表购物项)

    • 好的,我们先来写购物项实体吧,等会再写购物车!
    
    	/*购物项代表的是当前书,并表示该书出现了几次*/
    	public class CartItem {
    	
    	    private Book book;
    	    private int quantity;
    	
    	    //该购物项(书--不一定只有一本)的价钱应该等于书的数量*价格
    	    private double price;
    	
    		
    		//书的价钱*数量
    	    public double getPrice() {
    	        return book.getPrice() * this.quantity;
    	    }
    	
    	    public Book getBook() {
    	        return book;
    	    }
    	
    	    public void setBook(Book book) {
    	        this.book = book;
    	    }
    	
    	    public int getQuantity() {
    	        return quantity;
    	    }
    	
    	    public void setQuantity(int quantity) {
    	        this.quantity = quantity;
    	    }
    	    
    	    public void setPrice(double price) {
    	        this.price = price;
    	    }
    	}
    
    
    
    • 购物车实体
    
    
    	/*该类代表的是购物车*/
    	public class Cart {
    	
    	    //关键字是书籍的id,值是书
    	    private Map<String, CartItem> bookMap = new LinkedHashMap<>();
    	
    	    //代表着购物车的总价
    	    private double price;
    	
    	
    	    //把购物项(用户传递进来的书籍)加入到购物车里边去,也应该是购物车的功能
    	    public void addBook(Book book) {
    	
    	        //获取得到购物项
    	        CartItem cartItem = bookMap.get(book.getId());
    	
    	        //判断购物车是否存在该购物项,如果不存在
    	        if (cartItem == null) {
    	
    	            //创建这个购物项对象
    	            cartItem = new CartItem();
    	
    	            //将用户传递过来的书籍作为购物项
    	            cartItem.setBook(book);
    	
    	            //把该购物项的数量设置为1
    	            cartItem.setQuantity(1);
    	
    	            //把购物项加入到购物车去
    	            bookMap.put(book.getId(), cartItem);
    	        } else {
    	
    	            //如果存在该购物项,将购物项的数量+1
    	            cartItem.setQuantity(cartItem.getQuantity() + 1);
    	        }
    	    }
    	
    	    //购物车的总价就是所有购物项的价格加起来
    	    public double getPrice() {
    	
    	        double totalPrice = 0;
    	
    	        for (Map.Entry<String, CartItem> me : bookMap.entrySet()) {
    	
    	            //得到每个购物项
    	            CartItem cartItem = me.getValue();
    	
    	            //将每个购物项的钱加起来,就是购物车的总价了!
    	            totalPrice += cartItem.getPrice();
    	        }
    	
    	        return totalPrice;
    	    }
    	
    	
    	    public Map<String, CartItem> getBookMap() {
    	        return bookMap;
    	    }
    	
    	    public void setBookMap(Map<String, CartItem> bookMap) {
    	        this.bookMap = bookMap;
    	    }
    	
    	
    	    public void setPrice(double price) {
    	        this.price = price;
    	    }
    	}
    
    
    

    ③数据库

    这里就直接用集合模拟数据库了,简单的domo而已。

    
    	//既然是购物车案例,应该会有增删的操作,通过关键字查询书籍,所以使用LinkedHashMap集合
        private static Map<String, Book> map = new LinkedHashMap<>();
        
        static {
            map.put("1",new Book("1", "java", "zhongfucheng", "好书", 99));
            map.put("2",new Book("2", "javaweb", "ouzicheng", "不好的书", 44));
            map.put("3",new Book("3", "ajax", "xiaoming", "一般般", 66));
            map.put("4",new Book("4", "spring", "xiaohong", "还行", 77));
        }
    
        public static Map<String, Book> getAll() {
    
    
            return map;
        }
    
    

    ④开发dao

    dao层应该至少提供获取所有的书籍根据关键字获取得到书籍

    
    public class BookDao {
    
        //获取存放着书籍的Map集合
        public Map getAll() {
            return BookDB.getAll();
        }
    
        //根据关键字获取某本书籍
        public Book find(String id) {
            return BookDB.getAll().get(id);
        }
    }
    
    
    

    ⑤开发service#

    service层就是对DAO层的一个封装

    
    
    	public class BusinessService {
    	
    	    BookDao bookDao = new BookDao();
    	
    	    /*列出所有的书*/
    	    public Map getAll() {
    	
    	        return bookDao.getAll();
    	    }
    
    		/*根据书的id获取书*/
    	    public Book findBook(String id) {
    	        return bookDao.find(id);
    	    }
    	
    	    //...待会还有其他的功能再从这里补充!
    	}
    
    
    

    ⑥开发web

    列出所有的书

    开发提供JSP页面的Servlet

            //调用service层的方法,获取得到存放书籍的Map集合
            BusinessService businessService = new BusinessService();
            Map books = businessService.getAll();
            
            //存放在request域对象中,交给jsp页面显示
            request.setAttribute("books", books);
            
            //跳转到jsp页面中
            request.getRequestDispatcher("/WEB-INF/listBook.jsp").forward(request, response);
    
    

    开发显示所有书籍的jsp

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <html>
    <head>
        <title>显示所有的书籍</title>
    </head>
    <body>
    
    <%--Servlet传递过来的是一个Map对象,要显示所有的书籍,就需要遍历Map集合(EL表达式和JSTL标签合用)--%>
    <table border="1px">
        <tr>
            <td>书籍编号</td>
            <td>名称</td>
            <td>作者</td>
            <td>详细信息</td>
            <td>价格</td>
        </tr>
    
        <c:forEach items="${books}" var="me">
            <tr>
                <td>${me.key}</td>
                <td>${me.value.name}</td>
                <td>${me.value.author}</td>
                <td>${me.value.description}</td>
                <td>${me.value.price}</td>
            </tr>
        </c:forEach>
    
    
    </table>
    
    </body>
    </html>
    
    
    

    购买操作

    作为购物车的案例,怎么能没有购买的操作呢?于是乎就增加购买的操作

    开发处理购买的Servlet

            //获取得到传递过来的id
            String id = request.getParameter("bookid");
    
            //把用户想要买的书放到购物车上
    		//用户不单单只有一个,要让购物车上只为当前的用户服务,就需要用到会话跟踪技术了
    		Cart cart = (Cart) request.getSession().getAttribute("cart");
    
            //如果当前用户还没有点击过购买的商品,那么是用户的购物车是空的
            if (cart == null) {
                cart = new Cart();
                request.getSession().setAttribute("cart", cart);
            }
    
            //调用BussinessService的方法,实现购买功能!
            BusinessService businessService = new BusinessService();
            businessService.buyBook(id, cart);
    
            //跳转到购物车显示的页面上
            request.getRequestDispatcher("/listCart.jsp").forward(request, response);
    
    
    • 在我们前面开发BusinessService时,是没有buyBook()这个方法的!下面更新了BusinessService的代码
    
    
        /*
        * 在购买书籍的时候,我们发现需要将书籍添加到购物车上
        * 如果我们直接在Servlet上使用Cart实体对象的addBook()和BookDao对象的find()方法,是可以完成功能的
        * 
        * 但是,这样web层的程序就跟Dao层的耦合了,为了代码性的健壮性和解耦,我们在BusinessService中对他俩进行封装
        * 
        * 于是有了buyBook()这个方法!
        * */
        
        /*把用户想买的书籍添加到当前用户的购物车上*/
        public void buyBook(String id, Cart cart) {
    
            Book book = bookDao.find(id);
            cart.addBook(book);
    
        }
    
    

    购物车的页面

    • 初步把购物项的信息显示出来
    
    	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
    	<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    	<html>
    	<head>
    	    <title>购物车显示页面</title>
    	</head>
    	<body>
    	<h1>购物车显示页面</h1>
    	
    	<%--empty函数是判断集合中有没有元素--%>
    	<%--如果购物车是没有任何购物项的--%>
    	<c:if test="${empty(cart.bookMap)}">
    	    <h1>您还没有购买过任何的书籍呀!</h1>
    	</c:if>
    	
    	<%--如果购物车有购物项,就应该把购物项的信息显示给用户--%>
    	<c:if test="${!empty(cart.bookMap)}">
    	
    	    <table border="1px">
    	        <tr>
    	            <td>书籍编号</td>
    	            <td>名称</td>
    	            <td>数量</td>
    	            <td>小计</td>
    	            <td>操作</td>
    	        </tr>
    	        <c:forEach items="${cart.bookMap}" var="me">
    	            <tr>
    	                <td>${me.key}</td>
    	                <td>${me.value.book.name}</td>
    	                <td>${me.value.quantity}</td>
    	                <td>${me.value.price}</td>
    	                <td><a href="#">删除</a></td>
    	            </tr>
    	        </c:forEach>
    	        <tr>
    	            <td colspan="2"><a href="#">清空购物车</a></td>
    	
    	            <td colspan="2">合计:</td>
    	            <td>${cart.price}</td>
    	        </tr>
    	
    	    </table>
    	
    	</c:if>
    	
    	
    	</table>
    	
    	</body>
    	</html>
    
    
    
    
    • 效果是这样子的:


    删除购物车商品

    想要删除购物车中的商品,也很简单,把删除操作挂在超链接上,超链接指向DeleteCartServlet,并将想要删除的书本的id带过去(不将id带过去,服务器哪知道你要删除的是哪个)

    
    	<td><a href="${pageContext.request.contextPath}/DeleteCartBook?bookid=${me.key}">删除</a></td>
    
    

    开发DeleteCartBook的Servlet

    
            //获取得到用户想要删除哪个书本的id
            String id = request.getParameter("bookid");
    
            //获取该用户相对应的购物车对象
            Cart cart = (Cart) request.getSession().getAttribute("cart");
    
            try {
                //删除购物车的商品,也应该是在BusinessService中有的功能,于是乎又回到BusinessService中写代码
                BusinessService businessService = new BusinessService();
                businessService.deleteBook(id, cart);
    
                //删除购物车的商品后,也应该直接跳转回去购物车的显示页面中
                request.getRequestDispatcher("/WEB-INF/listCart.jsp").forward(request, response);
    
    
            } catch (CartNotFoundException e) {
                request.setAttribute("message", "购物车空了!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
    
            } catch (Exception e) {
                e.printStackTrace();
                request.setAttribute("message", "删除中出现了异常~待会再试试呗!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
            }
    
    
    • BusinessService又多了一个功能
    
        /*用户要在购物车中删除某个购物项*/
        public void deleteBook(String id, Cart cart) throws CartNotFoundException {
    
            //如果用户是直接访问DeleteCartBook的Servlet的,在session中是没有cart这个属性的!
            //告诉用户购物车是空的
            if (cart == null) {
                throw new CartNotFoundException("购物车为空");
            }
    
            //把购物项移除出去集合就行了!
            cart.getBookMap().remove(id);
        }
    
    

    效果:

    多本一起购买

    从上面的gif我们就可以发现,如果我重复买一本书,需要一本一本地点!这样会非常麻烦!

    我们要怎么实现:用户想要买多少本,购物车的数量就修改为多少本呢

    在购物车上,数量的值改成是输入框

    
    	<td><input type="text" name="quantity" value="${me.value.quantity}"></td>
    
    

    效果:

    好的,现在我们已经能够把数量随自己想要多少本,就改成是多少了。现在主要的问题就是,怎么在改的同时,数据也及时地更新?

    写javascript代码,让输入框的信息提交给服务器

    我们写javascript的代码,监控着输入框的变动,如果有变动,就响应事件,将变动的数据传递给服务器,更新数据!

    
    
        <script type="text/javascript">
    
            /*
            * @input 将输入框本身填入(这样可以获取得到输入框的值)
            * @id   将书本的id传递进来,告诉服务器是修改哪一个购物项(书)
            * @oldValue 原本的值,如果用户不想修改了,就修改为原本的值(下面会询问用户是否确定修改)
            * */
            function update(input,id,oldValue) {
    
                //获取得到输入框的数据
                var quantity = input.value;
    
                //询问用户是否真的修改
                var b = window.confirm("你确定修改吗?");
    
                //如果确定修改,就跳转到修改的Servlet上
                if(b) {
                    window.location.href = "${pageContext.request.contextPath}/UpdateQuantity?bookid=" + id + "&quantity=" + quantity + "";
                }else {
    
                    //如果不确定修改,把输入框的数据改成是原来的
                    input.value = oldValue;
                }
            }
        </script>
    
    

    编写UpdateQuantity的Servlet

    
            //获取得到用户想要修改哪一本书的id和相对应的数量
            String id = request.getParameter("bookid");
            String quantity = request.getParameter("quantity");
    
            //得到当前用户的购物车
            Cart cart = (Cart) request.getSession().getAttribute("cart");
    
    
            try {
    
                //调用BusinessService的方法去修改对应的数据
                BusinessService businessService = new BusinessService();
                businessService.updateQuantity(id, cart, quantity);
    
                //修改完再跳转回去购物车的页面中
                request.getRequestDispatcher("/WEB-INF/listCart.jsp").forward(request, response);
    
            } catch (CartNotFoundException e) {
                e.printStackTrace();
                request.setAttribute("message", "购物车是空的!");
                request.getRequestDispatcher("message.jsp").forward(request, response);
            }
    
    
    

    BusinessService增添了updateQuantity()方法

    
        public void updateQuantity(String id, Cart cart, String quantity) throws CartNotFoundException {
    
    
            //如果用户是直接访问DeleteCartBook的Servlet的,在session中是没有cart这个属性的!
            //告诉用户购物车是空的
            if (cart == null) {
                throw new CartNotFoundException("购物车为空");
            }
    
    
            //通过书的id获取得到购物车的购物项,再修改购物项的数量即可!(因为书的id和获取购物项的关键字是一致的!)
            cart.getBookMap().get(id).setQuantity(Integer.parseInt(quantity));
    
        }
    
    
    • 效果如下gif


    清空购物车

    清空购物车的做法和上面是类似的!也是首先通过javaScript代码询问用户是否要清空,如果要清空就跳转到相对应的Servlet中把购物车的数据清空了!

    在清空购物车的链接上绑定事件

    
    	<td colspan="2">
    		<a href="${pageContext.request.contextPath}/ClearCart" onclick=" return clearCart()" >清空购物车</a>
    	</td>
    
    

    javaScript代码做逻辑判断

            function clearCart() {
    
                var b = window.confirm("你确定要清空购物车吗?");
    
                //如果用户确定,就跳转到相对应的Servlet上
                if(b) {
                    return true;
                }else {
                    return false;
                }
            }
    
    

    编写ClearCart代码

    
            //得到用户相对应的购物车
            Cart cart = (Cart) request.getSession().getAttribute("cart");
    
            //调用相对应BusinessService的方法
            BusinessService businessService = new BusinessService();
    
            try {
    
                //清空购物车【实际上就是清空购物车的Map集合中的元素】
                businessService.clearCart(cart);
    
                //返回给购物车显示页面
                request.getRequestDispatcher("/WEB-INF/listCart.jsp").forward(request, response);
    
            } catch (CartNotFoundException e) {
                e.printStackTrace();
                request.setAttribute("message", "购物车是空的!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
            }
    
    
    

    在BusinessService中添加清空购物车功能

    
        public void clearCart(Cart cart) throws CartNotFoundException {
    
            //如果用户是直接访问DeleteCartBook的Servlet的,在session中是没有cart这个属性的!
            //告诉用户购物车是空的
            if (cart == null) {
                throw new CartNotFoundException("购物车为空");
            }
    
            //清空所有的购物项
            cart.getBookMap().clear();
    
    
        }
    
    
    • 效果:


    总结

    1. 购物车的应该是一个以id作为key,以购物项作为value的一个Map集合。这样设计的话,我们在显示商品的时候,就不会重复显示同一种类型的商品了。
    2. 购物项代表着该商品,并且应该给予购物项 数量和价钱的属性。购物项的价钱应该是数量*单价
    3. 购物车应该提供把商品添加到购物车的功能。当然啦,购物项代表着商品,所以首先要判断该购物车是否有同类的商品,如果有,直接在购物项的数量上+1即可的。如果没有,就设置该购物项的属性,并把购物项添加到购物车中
    4. 购物车的总价就是所有购物项的总价
    5. 无论是增删改查购物车的数据,其实就是操作这个集合

    如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,可以关注微信公众号:Java3y

  • 相关阅读:
    设计模式复习-单例模式
    设计模式复习-组合模式
    设计模式复习-迭代器模式
    设计模式复习-备忘录模式
    PAT 1085 PAT单位排行 (Microsoft_zzt)
    PAT L1-034 点赞
    PAT L1-032 Left-pad
    PAT 甲级 1046 Shortest Distance
    PAT 甲级 1077 Kuchiguse
    PAT 甲级 1027 Colors in Mars
  • 原文地址:https://www.cnblogs.com/Java3y/p/8467778.html
Copyright © 2011-2022 走看看