程序解耦 购物车操作 生成订单 (网上商城三)
2017-09-21 09:17
337 查看
程序解耦合的解决方式:
工厂+配置文件+反射:编写好工厂类,然后在需要调用不同实现类Servlet中使用工厂,接口new实现类由工厂参数中传入的字段通过映射的方式找到对应的实现类就可以使用实现类了.第一步:工厂的配置文件ApplicationContext.xml:
<?xml version="1.0"encoding="UTF-8"?> <beans> <bean id="userDao"class="com.itheima.store.dao.impl.UserDaoImpl"/> <bean id="productDao"class="com.itheima.store.dao.impl.ProductDaoImpl"/> <bean id="categoryDao"class="com.itheima.store.dao.impl.CategoryDaoImpl"/> <bean id="orderDao"class="com.itheima.store.dao.impl.OrderDaoImpl"/> <bean id="userService"class="com.itheima.store.service.impl.UserServiceImpl"/> <bean id="productService"class="com.itheima.store.service.impl.ProductServiceImpl"/> <bean id="categoryService"class="com.itheima.store.service.impl.CategoryServiceImpl"/> <bean id="orderService"class="com.itheima.store.service.impl.OrderServiceImpl"/> </beans>
第二步:编写工厂类:
public class BeanFactory { public static ObjectgetBean(String id){ SAXReaderreader = new SAXReader(); try { // 解析XML :dom4j Documentdocument = reader.read(BeanFactory.class.getClassLoader().getResourceAsStream("applicationContext.xml")); // 获得class中的内容. ElementbeanElement = (Element) document.selectSingleNode("//bean[@id='"+id+"']"); Stringvalue = beanElement.attributeValue("class"); System.out.println(value); // 反射生成实例 : Classclazz = Class.forName(value); return clazz.newInstance(); }catch (Exception e) { e.printStackTrace(); } return null; } public static void main(String[] args) { BeanFactory.getBean("productDao"); } }
第三步: 使用工厂:
// CategoryDaocategoryDao = new CategoryDaoImpl();CategoryDaocategoryDao =(CategoryDao)BeanFactory.getBean("categoryDao");
优点: 完成程序的解耦合, 并且对程序进行底层切换的时候不用修改源代码.
依赖注入:在成员中声明一下需要用到的类重写set方法,然后就可以直接使用类名.调用其中的方法.
购物模块的实体封装:
两个实体对象;( 购物车对象和购物项的实体) 一个购物车中可以有多个购物项.
一.编写cartItem购物项:
购物项中需要改造一下小计的get方法://购物项
public
class CartItem {
private Productproduct ; //商品
private Integercount ; //数量
private Doublesubtotal ; //小计
public Double getSubtotal() {
returncount*product.getShop_price();
}
二.编写cart购物车
publicclass Cart {
private Doubletotal = 0.0 ;
private Map<String , CartItem>map =new LinkedHashMap<String ,CartItem>();
//list对于购物的删除操作比较复杂,使用map可以直接由key删除.使用商品的ID作为key,购物项作为value
//购物车的方法
//将购物项添加到购物车
public
void addCart(CartItem cartItem){
//购物车中是否已经有该商品
String pid =
cartItem.getProduct().getPid();
if(map.containsKey(pid)){
Integercount1 =map.get(pid).getCount(); //获得原来购物车中的数量
Integercount2 =cartItem.getCount(); //获得现在购物项中的数量
map.get(pid).setCount(count1+count2); //设置新的购物车中的数量
}else{ //购物车中没有该商品
map.put(pid,cartItem);
}
total +=
cartItem.getSubtotal(); //计算总金额
}
//从车中移除购物项 ;
public
void removeCart(String pid){
CartItem cartItem =map.remove(pid); //移除商品,并且返回移除的商品
total -=
cartItem.getSubtotal(); //总金额减去移除商品的小计
}
//清空购物车
public
void clearCart(){
//清空map集合
map.clear();
//总金额为0
total = 0.0;
}
public Double getTotal() {
returntotal;
}
public Map<String, CartItem> getMap() {
returnmap;
}
}
购物模块的添加到购物车的代码实现
在商品详情页面点击【加入购物车】:添加到Servlet:
调用封装的购物车对象addCart的方法:
页面跳转:(购物车的页面)
第一步:编写product_info.jsp页面
<ahref="${pageContext.request.contextPath }">首页 ></a></div>
<formid ="form1"action="${pageContext.request.contextPath
}/CartServlet" method="post">
<inputtype="hidden"name="method" value="addCart">
//传方法名过去
<inputtype="hidden"name="pid" value="${p.pid
}"> //添加pid字段
<divstyle="margin:0 auto;width:950px;">
<divclass="col-md-6">
<imgstyle="opacity:1;width:400px;height:350px;"title=""class="medium"src="${pageContext.request.contextPath
}/${p.pimage }">
</div>
<divclass="col-md-6">
<div><strong>${p.pname }</strong></div>
<divstyle="border-bottom:1px dotted #dddddd;width:350px;margin:10px
0 10px 0;">
<div>编号:${p.pid }</div>
</div>
<divstyle="margin:10px 0 10px 0;">商城价:<strongstyle="color:#ef0101;">¥:${p.shop_price
}元/份</strong> 参 考 价:<del>¥${p.market_price }元/份</del>
</div>
<divstyle="margin:10px 0 10px 0;">促销:<atarget="_blank"title="限时抢购
(2014-07-30 ~ 2015-01-01)"style="background-color:#f07373;">限时抢购</a></div>
<divstyle="padding:10px;border:1px
solid #e7dbb1;width:330px;margin:15px 0 10px 0;;background-color:#fffee6;">
<divstyle="border-bottom:1px solid #faeac7;margin-top:20px;padding-left:10px;">购买数量:
<inputid="count"name="count"value="1"maxlength="4"size="10"type="text"></div>
<divstyle="margin:20px 0 10px 0;;text-align:center;">
<ahref="javascript:document.getElementById('form1').submit()">//提交按钮
<inputstyle="background:url('./images/product.gif')no-repeat scroll 0 -600px
rgba(0, 0, 0, 0);height:36px;width:127px;"value="加入购物车"type="button">
</a> 收藏商品</div>
</div>
</div>
</div>
</form>
第二步:编写CartServlet页面中的addCart方法:
* 购物模块的servletpublic
class CartServlet extends BaseServlet {
private
static final
long serialVersionUID = 1L;
//添加到购物车执行的addCart方法
public StringaddCart(HttpServletRequestreq , HttpServletResponse resp ) {
try{
//接收表单提交过来的参数
Stringpid =req.getParameter("pid");
Integercount = Integer.parseInt(req.getParameter("count"));
//封装CartItem
CartItemcartItem = new CartItem();
cartItem.setCount(count);
ProductServiceproductService =(ProductService) BeanFactory.getBean("productService");
Productproduct =productService.findByPid(pid);
cartItem.setProduct(product);
//调用cart中的添加到购物车的add方法:购物车信息不能每次都new
Cart,
Cart cart = getCart(req); //先从session中获得,如果没有再new
Cart,所以要传req过去
cart.addCart(cartItem);
//页面跳转 , 转发过去的话容易出现重复刷新的问题,所以要不是用重定向,要不使用令牌机制
resp.sendRedirect(req.getContextPath()+"/jsp/cart.jsp");
}catch(Exceptione ){
e.printStackTrace();
}
returnnull ;
}
private CartgetCart(HttpServletRequestreq ) {
HttpSessionsession =req.getSession();
Cart cart = (Cart)session.getAttribute("cart");
if(cart ==null ){
cart =new Cart();
session.setAttribute("cart",cart);
}
returncart;
}
}
第三步:编写cart.jsp页面;
<th>操作</th>
</tr>
<c:forEachvar="entry" items="${cart.map
}">
<trclass="active">
<tdwidth="60"width="40%">
<inputtype="hidden"name="id"value="22">
<imgsrc="${pageContext.request.contextPath }/${entry.value.product.pimage
}"width="70"height="60">
</td>
<tdwidth="30%">
<atarget="_blank">${entry.value.product.pname
}</a>
</td>
<tdwidth="20%">
¥${entry.value.product.shop_price}
</td>
<tdwidth="10%">
${entry.value.count}
</td>
<tdwidth="15%">
<spanclass="subtotal">¥${entry.value.subtotal}</span>
</td>
<td>
<ahref="javascript:;"class="delete">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
<divstyle="margin-right:130px;">
<divstyle="text-align:right;">
<emstyle="color:#ff6600;">
登录后确认是否享有优惠
</em> 赠送积分:<emstyle="color:#ff6600;">${cart.total
}</em> 商品金额:
<strongstyle="color:#ff6600;">¥${cart.total
}元</strong>
</div>
拿到map中value的写法:
清空购物车:
在购物车的页面中点击清除购物车的链接:提交到Servlet:
* 调用Cart中的clearCart的方法:
* 跳转到购物车页面:
一.Cart.jsp页面设置清空按钮;
<divstyle="text-align:right;margin-top:10px;margin-bottom:10px;"><ahref="${pageContext.request.contextPath }/CartServlet?method=clearCart"id="clear"class="clear">清空购物车</a>
二.编写CartServlet中clearCart方法:
public StringclearCart(HttpServletRequest req , HttpServletResponse resp ) { try{ Cartcart = getCart(req); cart.clearCart(); resp.sendRedirect(req.getContextPath()+"/jsp/cart.jsp"); }catch(Exception e ){ e.printStackTrace(); } return null ; }
三.购物车空时隐藏提交订单按钮等,提示为空
首先,条件中判断map为空需要用函数库来完成,所以页头引入函数库<%@
taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
再对展示内容加上是否为空的条件显示:
<%@
include file="menu.jsp"%>
<c:iftest="${fn:length(cart.map)== 0
}">
<h1>购物车控控的~</h1>
<imgalt="此处应该有图片"src="">
</c:if>
<c:iftest="${fn:length(cart.map)!= 0 }">
下面是购物项商品显示内容
<divclass="container">
<divclass="row">
移除购物项:
在购物车的页面中点击删除的链接:添加到Servlet:
* 调用Cart中的removeCart的方法:
* 跳转到购物车页面:
一.设置删除按钮
<ahref=""onclick="del('${entry.value.product.pid}')" class="delete">删除</a><scripttype="text/javascript">
function del(pid){
var flag =confirm("确定要删除吗?");
if(flag ==true){
window.location.href="${pageContext.request.contextPath}/CartServlet?method=removeCart&pid="+pid;
}
}
</script>
二.CartServlet中编写removeCart方法:
public String removeCart(HttpServletRequest req ,HttpServletResponse resp ) { try{ //移除购物项的功能 Stringpid = req.getParameter("pid"); Cartcart = getCart(req); cart.removeCart(pid); resp.sendRedirect(req.getContextPath()+"/jsp/cart.jsp"); }catch(Exception e ){ e.printStackTrace(); } return null ; }
订单模块订单数据的封装
商品与订单表是多对多的关系,所以采用中间表的形式, 使之分别与中间表形成一对多的关系, 也就是使用两个特殊的一对多来描述多对多的关系. 在多的一方创建外键 . 本案例中订单表与订单项是一对多的关系,而且订单项与商品表也是一对多的关系 , 顾商品与订单形成多对多的关系 .第一步:创建表;
在数据库里创建order订单表, 和orderitem订单项表.第二步:创建实体
Order订单表:public
class Order {
private Stringoid ;
private Date
ordertime ; //订单时间
private Doubletotal ; //总金额
private Integerstate ; //1未付款, 2已付款未发货
, 3 已发货没确认售货, 4确认收货
private String address ; //地址
private Stringname ; //姓名
private String telephone ;
private User user ; //订单属于哪个用户
private List<OrderItem>orderItems = new
ArrayList<OrderItem>(); //一个订单下有多个订单项//在查询订单的时候订单项需要显示,就一起给查了,无需两次.把属于这个订单的订单项一起给查出来
public String getOid() {
OrderItem订单项:
public class OrderItem { private String itemid ; private Integer count ; //数量 private Double subtotal ; // 小计 private Product product ; //商品ID和订单ID private Order order ; //这个订单项是属于哪个订单的 public StringgetItemid() { return itemid; }
生成订单的功能:
在购物车的页面中点击提交订单:提交到Servlet中:
* 事务管理:向订单表和订单项表插入记录.
* 页面跳转到订单页面:
第一步:cart.jsp页面中提交订单按钮:
<ahref="${pageContext.request.contextPath }/OrderServlet?method=saveOrder"><inputtype="button"width="100"value="提交订单"name="submit"border="0"style="background:url('${pageContext.request.contextPath
}/images/register.gif') no-repeat scroll 0 0 rgba(0, 0, 0,0);
height:35px;width:100px;color:white;">
</a>
第二步:编写OrderServlet和其中的saveOrder方法:
编写servlet之前,先建好orderService类,orderServiceImpl类和OrderDao类, OrderDaoImpl类.
并且在工厂模式的配置文件中添加好相应的
<beanid="orderDao"class="com.itheima.store.dao.impl.OrderDaoImpl"/>
<bean
id="orderService"class="com.itheima.store.service.impl.OrderServiceImpl"/>
public
class OrderServlet extends BaseServlet {
private
static final
long serialVersionUID = 1L;
//生成订单执行的方法
public StringsaveOrder(HttpServletRequestreq , HttpServletResponseresp){
//自己封装一个Order对象以供下面保存用
Orderorder =new Order();
order.setOid(UUIDUtils.getUUID());
//地址姓名电话可以先不用设置,因为在付款之前的时候再填也可
order.setOrdertime(new Date());
order.setState(1);//1未付款
//设置总金额 从购物车中获得总金额
Cartcart = (Cart)req.getSession().getAttribute("cart");
if(cart ==null ){ //此处可以写一个权限的过滤器,没登录,购物车订单都不让访问
req.setAttribute("msg","购物车是空的哟~");
return"/jsp/msg.jsp";
}//我们不从页面显示的总价处拿来做总金额是因为前台不安全,要时刻考虑数据的安全
order.setTotal(cart.getTotal()); //如果不为空就从购物车中拿出来设置
//设置订单所属的用户 从登陆的信息中获得用户信息
UserexistUser = (User)req.getSession().getAttribute("existUser");
if(existUser ==null){
req.setAttribute("msg","您还没有登录哟~");
return"/jsp/login.jsp";
}
order.setUser(existUser);
//设置订单项 ,商品集合是存在cart中的所以我们从以上cart中拿来封
for(CartItemcartItem :cart.getMap().values()){
//遍历一个,封装一个放进订单项中成员List<orderItem>中
OrderItemorderItem =new OrderItem();
orderItem.setItemid(UUIDUtils.getUUID());
orderItem.setCount(cartItem.getCount());
orderItem.setSubtotal(cartItem.getSubtotal());
orderItem.setProduct(cartItem.getProduct());
orderItem.setOrder(order);
order.getOrderItems().add(orderItem);
}
//调用业务层完成保存
OrderServiceorderService =(OrderService) BeanFactory.getBean("orderService");
orderService.save(order);
//清空购物车
cart.clearCart();
//页面跳转
req.setAttribute("order",order);
return"/jsp/order_info.jsp" ;
}
}
第三步.编写OrderServiceImpl实现类,开启开启事务保存订单和订单项
public class OrderServiceImpl implements OrderService { public void save(Order order) { Connectionconn = JDBCUtils.getConnection(); try{//使用事务管理 //开启事务 conn.setAutoCommit(false); //执行保存操作 OrderDaoorderDao = (OrderDao)BeanFactory.getBean("orderDao"); orderDao.save(conn , order); //循环去保存订单中的订单项 for (OrderItem orderItem : order.getOrderItems()){ orderDao.saveOrderItem(conn , orderItem); } //提交事务 DbUtils.commitAndCloseQuietly(conn); }catch(Exception e ){ e.printStackTrace(); DbUtils.rollbackAndCloseQuietly(conn); } } }
加上OrderDaoImpl中的save功能代码:
public class OrderDaoImpl implements OrderDao { public void save(Connectionconn, Order order) throws SQLException { QueryRunnerqr = new QueryRunner(); Stringsql = "insertinto orders values ( ?,?,?,?,?,?,?,?)"; Object[]params = {order.getOid() , order.getOrdertime() ,order.getTotal() , order.getState() ,order.getAddress() , order.getName() , order.getTelephone() , order.getUser().getUid() }; qr.update(conn , sql , params); }
public voidsaveOrderItem(Connection conn, OrderItem orderItem) throws SQLException { QueryRunnerqr = new QueryRunner(); Stringsql = "insertinto orderItem values ( ?,?,?,?,?)"; Object[]params = {orderItem.getItemid() , orderItem.getCount() , orderItem.getSubtotal() , orderItem.getProduct().getPid() , orderItem.getOrder().getOid()}; qr.update(conn , sql , params); } }
第四步:生成订单后显示到页面
<strong>订单详情</strong> <table class="tabletable-bordered"> <tbody> <tr class="warning"> <th colspan="5">订单编号:${order.oid } </th> </tr> <tr class="warning"> <th>图片</th> <th>商品</th> <th>价格</th> <th>数量</th> <th>小计</th> </tr> <c:forEach var="orderItem" items="${order.orderItems }"> <tr class="active"> <td width="60"width="40%"> <input type="hidden"name="id" value="22"> <img src="${pageContext.request.contextPath}/${orderItem.product.pimage}"width="70" height="60"> </td> <td width="30%"> <a target="_blank">${orderItem.product.pname}</a> </td> <td width="20%"> ¥${orderItem.product.shop_price } </td> <td width="10%"> ${orderItem.count} </td> <td width="15%"> <span class="subtotal">¥${orderItem.subtotal}</span> </td> </tr> </c:forEach> </tbody> </table> </div> <div style="text-align:right;margin-right:120px;"> 商品金额: <strong style="color:#ff6600;">¥${order.total }元</strong> </div>
相关文章推荐
- 网上图书商城项目学习笔记-018生成订单
- 网上商城之购物车的3种实现方式
- 浅析PetShop程序中的购物车和订单处理模块(Profile技术,异步MSMQ消息)
- php网上商城购物车设计代码分享
- 【SSH网上商城项目实战26】完成订单支付后的短信发送功能
- 【SSH网上商城项目实战17】购物车基本功能的实现
- 国美网上商城以用户IP相同为由取消订单
- 【SSH网上商城项目实战19】订单信息的级联入库以及页面的缓存问题
- 一个能为企业带来订单的网上商城是如何运营的?
- SSH框架网上商城项目第26战之订单支付后发送短信提醒
- 浅析Microsoft .net PetShop程序中的购物车和订单处理模块(Profile技术,异步MSMQ消息)
- 网上商城迁移的操作实例
- 17.12.21,web学习第三十天,还有一年,努力吧青年 商城项目第三天购物车操作
- [编写高质量代码:改善java程序的151个建议]建议72 生成字列表后不要再操作原列表
- 某商城抢购心得--论网页慢该如何操作才能最快提交订单
- 编译C/C++语言程序源码生成的汇编语言程序源码中的.fnstart,.fnend等伪操作
- 项目之网上商城 购物车 总结 更新中。。。
- 浅析Microsoft .net PetShop程序中的购物车和订单处理模块(Profile技术,异步MSMQ消息)
- 网上图书商城4--购物车模块1
- 浅析Microsoft .net PetShop程序中的购物车和订单处理模块(Profile技术,异步MSMQ消息) 选择自 wangyihust 的 Blog