①构建开发环境为了巩固MVC的开发模式,下面就写一个购物车的小案例..javascript
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
}
可能咱们会这样设计购物车html
/*该类表明的是购物车*/
public class Cart {
//关键字是书籍的id,值是书
private Map<String, Book> bookMap = new LinkedHashMap<>();
}
上面的作法是不合适的,试想一下:若是我要购买两本相同的书,购物车的页面上就出现了两本书,而不是书*2。买三本相同的书就在购物页面上出现三本书,而不是书*3.java
所以,Map集合的值不能是Book对象,那咱们怎么才能解决上面所说的问题呢?咱们最经常使用的就是,再写一个实体CartItem(表明购物项)web
好的,咱们先来写购物项实体吧,等会再写购物车!ajax
/*购物项表明的是当前书,并表示该书出现了几回*/
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;
}
}
购物车实体spring
/*该类表明的是购物车*/③数据库
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集合④开发dao
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层应该至少提供获取全部的书籍和根据关键字获取获得书籍服务器
public class BookDao {⑤开发service
//获取存放着书籍的Map集合
public Map getAll() {
return BookDB.getAll();
}
//根据关键字获取某本书籍
public Book find(String id) {
return BookDB.getAll().get(id);
}
}
service层就是对DAO层的一个封装微信
public class BusinessService {⑥开发web
BookDao bookDao = new BookDao();
/*列出全部的书*/
public Map getAll() {
return bookDao.getAll();
}
/*根据书的id获取书*/
public Book findBook(String id) {
return bookDao.find(id);
}
//...待会还有其余的功能再从这里补充!
}
//调用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);
显示全部的书籍 书籍编号 名称 做者 详细信息 价格 ${me.key} ${me.value.name} ${me.value.author} ${me.value.description} ${me.value.price}
做为购物车的案例,怎么能没有购买的操做呢?因而乎就增长购买的操做!session
//获取获得传递过来的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" %> 购物车显示页面 购物车显示页面 %--empty函数是判断集合中有没有元素--%> %--若是购物车是没有任何购物项的--%> 您尚未购买过任何的书籍呀! %--若是购物车有购物项,就应该把购物项的信息显示给用户--%> 书籍编号 名称 数量 小计 操做 ${me.key} ${me.value.book.name} ${me.value.quantity} ${me.value.price} 删除 清空购物车 合计: ${cart.price}
效果是这样子的:
想要删除购物车中的商品,也很简单,把删除操做挂在超连接上,超连接指向DeleteCartServlet,并将想要删除的书本的id带过去(不将id带过去,服务器哪知道你要删除的是哪一个)!
删除
//获取获得用户想要删除哪一个书本的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的代码,监控着输入框的变更,若是有变更,就响应事件,将变更的数据传递给服务器,更新数据!
<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>
//获取获得用户想要修改哪一本书的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);
}
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));
}
清空购物车的作法和上面是相似的!也是首先经过javaScript代码询问用户是否要清空,若是要清空就跳转到相对应的Servlet中把购物车的数据清空了!
清空购物车
function clearCart() {
var b = window.confirm("你肯定要清空购物车吗?");
//若是用户肯定,就跳转到相对应的Servlet上
if(b) {
return true;
}else {
return false;
}
}
//获得用户相对应的购物车
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);
}
public void clearCart(Cart cart) throws CartNotFoundException {
//若是用户是直接访问DeleteCartBook的Servlet的,在session中是没有cart这个属性的!
//告诉用户购物车是空的
if (cart == null) {
throw new CartNotFoundException("购物车为空");
}
//清空全部的购物项
cart.getBookMap().clear();
}
购物车的应该是一个以id做为key,以购物项做为value的一个Map集合。这样设计的话,咱们在显示商品的时候,就不会重复显示同一种类型的商品了。
购物项表明着该商品,而且应该给予购物项 数量和价钱的属性。购物项的价钱应该是数量*单价
购物车应该提供把商品添加到购物车的功能。固然啦,购物项表明着商品,因此首先要判断该购物车是否有同类的商品,若是有,直接在购物项的数量上+1便可的。若是没有,就设置该购物项的属性,并把购物项添加到购物车中
购物车的总价就是全部购物项的总价
不管是增删改查购物车的数据,其实就是操做这个集合
若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章的同窗,能够关注微信公众号:Java3y