图书商城【7】

今天来写Order模块,这个模块可以说是最复杂模块了,因为它和前面所有模块都有很大的关联,所以务必将这一块拿下,我们先进入到showCart页面,点击结算生成订单时,网页会跳转到order.jsp页面,在页面展示我们订单中的信息。当我们点击生成订单时,order.jsp
页面会向${pageContext.request.contextPath}/order提交, 表单中有一个隐藏域 <input type="hidden" name="method" value="add">
然后我们开始正式写Order模块,首先,我们还是先写domain,因为在数据库中order模块有order、orderItem(多对多操作)两张表,所以我们需要将order和orderitem全部写出来,另外,在Order用于查询订单时,我们也要将用户信息封装到Order中,并且由于一个用户的订单包含多个订单项,所以我们用List来储存订单项。在orderitem类中,要查询订单中商品信息时,可以将商品信息封装到OrderItem中。
下面的Order和OrderItem类
package cn.itcast.estore.domain;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

public class Order implements Serializable {

	private String id;

	private double money;

	private String receiverinfo;

	private int paystate;

	private Date orderTime;

	private int user_id;

	// 用于订单查询时,可以将用户信息也封装到Order中
	private String username;
	private String nickname;

	// 订单中包含多个订单项
	private List<OrderItem> orderItems;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public double getMoney() {
		return money;
	}

	public void setMoney(double money) {
		this.money = money;
	}

	public String getReceiverinfo() {
		return receiverinfo;
	}

	public void setReceiverinfo(String receiverinfo) {
		this.receiverinfo = receiverinfo;
	}

	public int getPaystate() {
		return paystate;
	}

	public void setPaystate(int paystate) {
		this.paystate = paystate;
	}

	public Date getOrderTime() {
		return orderTime;
	}

	public void setOrderTime(Date orderTime) {
		this.orderTime = orderTime;
	}

	public int getUser_id() {
		return user_id;
	}

	public void setUser_id(int user_id) {
		this.user_id = user_id;
	}

	public List<OrderItem> getOrderItems() {
		return orderItems;
	}

	public void setOrderItems(List<OrderItem> orderItems) {
		this.orderItems = orderItems;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getNickname() {
		return nickname;
	}

	public void setNickname(String nickname) {
		this.nickname = nickname;
	}

}
package cn.itcast.estore.domain;

public class OrderItem {

	private String order_id; // 订单号
	private String product_id; // 商品号
	private int buynum; // 购买数量

	// 要查询订单中商品信息时,可以将商品信息封装到OrderItem中.
	private String name;
	private double price;

	public String getOrder_id() {
		return order_id;
	}

	public void setOrder_id(String order_id) {
		this.order_id = order_id;
	}

	public String getProduct_id() {
		return product_id;
	}

	public void setProduct_id(String product_id) {
		this.product_id = product_id;
	}

	public int getBuynum() {
		return buynum;
	}

	public void setBuynum(int buynum) {
		this.buynum = buynum;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getPrice() {
		return price;
	}

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

}
接着我们开始写DAO层,OrderDao主要写对订单的增删查改,OrderItemDao主要写根据订单对订单项的增删查改。需要注意的是因为我们提交订单或者删除订单,Product数量要相应变化,所以我们也要对Product进行操作,增加相应操作的ProductDao类后面也会重新更新一下。
package cn.itcast.estore.dao;

import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import cn.itcast.estore.domain.Order;
import cn.itcast.estore.domain.User;
import cn.itcast.estore.utils.DataSourceUtils;

public class OrderDao {

	// 创建订单
	public void createOrder(Order order) throws SQLException {
		String sql = "insert into orders values(?,?,?,0,null,?)";

		QueryRunner runner = new QueryRunner();//不需要使用带参数构造方法

		runner.update(DataSourceUtils.getConnection(), sql, order.getId(),
				order.getMoney(), order.getReceiverinfo(), order.getUser_id());
	}

	// 根据用户查询订单
	public List<Order> findOrder(User user) throws SQLException {

		String sql = null;
		List<Order> orders = null;
		QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
		if ("admin".equals(user.getRole())) {
			sql = "select orders.*,username,nickname from orders,users where orders.user_id=users.id";

			orders = runner.query(sql, new BeanListHandler<Order>(Order.class));
		} else if("user".equals(user.getRole())) {
			sql = "select orders.*,username,nickname from orders,users where orders.user_id=users.id and user_id=?";
			orders = runner.query(sql, new BeanListHandler<Order>(Order.class),
					user.getId());
		}

		return orders;
	}
	//删除订单
	public void delOrder(String id) throws SQLException {

		String sql = "delete from orders where id=?";

		QueryRunner runner = new QueryRunner();

		runner.update(DataSourceUtils.getConnection(), sql, id);
	}
	//修改订单状态
	public void updateState(String id) throws SQLException {
	
		String sql="update orders set paystate=1 where id=?";
		
		QueryRunner runner = new QueryRunner();
		
		runner.update(sql,id);
		
	}

}

package cn.itcast.estore.dao;

import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import cn.itcast.estore.domain.Order;
import cn.itcast.estore.domain.OrderItem;
import cn.itcast.estore.utils.DataSourceUtils;

public class OrderItemDao {

	// 添加订单项
	public void addOrderItem(Order order) throws SQLException {

		List<OrderItem> items = order.getOrderItems();

		Object[][] params = new Object[items.size()][3];

		for (int i = 0; i < items.size(); i++) {

			OrderItem item = items.get(i);

			params[i][0] = item.getOrder_id();
			params[i][1] = item.getProduct_id();
			params[i][2] = item.getBuynum();
		}

		String sql = "insert into orderitem values(?,?,?)";

		QueryRunner runner = new QueryRunner();

		runner.batch(DataSourceUtils.getConnection(), sql, params);

	}

	// 根据订单查询订单项
	public List<OrderItem> findOrderItemByOrderId(Order order)
			throws SQLException {

		String sql = "select * from orderitem,products where orderitem.product_id=products.id and  order_id=?";
		QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());

		return runner.query(sql,
				new BeanListHandler<OrderItem>(OrderItem.class), order.getId());
	}

	// 根据订单id查询所有订单项
	public List<OrderItem> findOrderItemByOrderId(String id)
			throws SQLException {
		String sql = "select * from orderitem where order_id=?";
		QueryRunner runner = new QueryRunner();
		return runner.query(DataSourceUtils.getConnection(),sql,
				new BeanListHandler<OrderItem>(OrderItem.class), id);
	}

	//删除订单项
	public void delOrderItem(String id) throws SQLException {
		
		String sql="delete from orderItem where order_id=?";
		
		QueryRunner runner = new QueryRunner();
		
		runner.update(DataSourceUtils.getConnection(),sql,id);
	}
}

package cn.itcast.estore.dao;

import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import cn.itcast.estore.domain.Order;
import cn.itcast.estore.domain.OrderItem;
import cn.itcast.estore.domain.Product;
import cn.itcast.estore.utils.DataSourceUtils;

public class ProductDao {

	public void addProduct(Product p) throws SQLException {
		QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
		String sql = "insert into products values(?,?,?,?,?,?,?)";
		runner.update(sql, p.getId(), p.getName(), p.getPrice(),
				p.getCategory(), p.getPnum(), p.getImgurl(), p.getDescription());
	}

	public List<Product> findAll() throws SQLException {
		QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
		String sql = "select * from products";
		return runner.query(sql, new BeanListHandler<Product>(Product.class));
	}

	public Product findById(String id) throws SQLException {
		QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
		String sql = "select * from products where id=?";
		return runner.query(sql, new BeanHandler<Product>(Product.class), id);
	}

	// 修改商品的数量
	public void updateProductCount(Order order) throws SQLException {

		// 要修改的数量在哪?
		List<OrderItem> items = order.getOrderItems();

		Object[][] params = new Object[items.size()][2];

		for (int i = 0; i < items.size(); i++) {

			OrderItem item = items.get(i);
			params[i][0] = item.getBuynum();
			params[i][1] = item.getProduct_id();

		}

		String sql = "update products set pnum=pnum-? where id=?";

		QueryRunner runner = new QueryRunner();

		runner.batch(DataSourceUtils.getConnection(), sql, params);

		// for(OrderItem item:items){
		//
		// runner.update(sql,item.getBuynum(),item.getProduct_id());
		//
		// }
	}

	// 当删除订单时,修改商品数量
	public void updateProductCount(List<OrderItem> items) throws SQLException {

		Object[][] params = new Object[items.size()][2];

		for (int i = 0; i < items.size(); i++) {

			OrderItem item = items.get(i);
			params[i][0] = item.getBuynum();
			params[i][1] = item.getProduct_id();

		}

		String sql = "update products set pnum=pnum+? where id=?";

		QueryRunner runner = new QueryRunner();

		runner.batch(DataSourceUtils.getConnection(), sql, params);
	}

	public List<Product> findSell() throws SQLException {

		String sql = "select products.name,sum(buynum) as totalSaleNum from orders,orderItem,products where orders.id=orderItem.order_id and products.id=orderITem.product_id and orders.paystate=1 group by products.id order by totalSaleNum desc";

		QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
		return runner.query(sql, new BeanListHandler<Product>(Product.class));
	}
}
现在我们整理一下注意事项:
当订单生成后,需要对以下的表进行操作.
1.订单表中要插入数据
2.商品表中的商品数量要进行修改(修改商品的库存)
3.订单与用户之间也存在关系,添加订单时,也需要得到当前用户的id.
这时我们应想到,如果对数据库夺标进行操作时,就需要一个事务控制(DataSourceUtils)。
所以以上操作需要进行事务控制。
1.获取Connection时,要使用同一个,需要在DataSourceUtils中对获取Connection对象操作进行修改,将其放入到ThreadLocale中.
2.DbutilsQueryRunner 直接使用带参数的 参数类型是DataSource类型。new QueryRunner(DataSource ds);这个操作,在调用update,query方法,一般不会带Connection参数,这样,它就是一条sql一个事务。而现在我们需要事务管理,所以我们在使用QueryRunner时,就会不带参数 new QueryRunner(),而使用带Connection参数的update,query方法.
现在我们需要事务控制,所以我们在service层进行了事务的开启

大家看这张图,就拿add方法来说,一个add方法就要调用DAO的多个方法,都需要与数据库操作,而且操作方法两个是insert一个update,如果在添加过程中出现问题,就要对数据进行回滚,保证数据完整。所以我们需要做开启事务、调用操作、提交(如果出现问题,需要事务回滚),同时在添加订单项时,使用了批处理,因为订单与商品之间存在多对多关系,那么我们的中间表orderItem,它就有可能有多条数据,所以我们使用了QueryRuner的batch方法完成添加订单项操作。注意注意的是:当我们操作完成后,一定要将Connection对象从ThreadLocale中remove掉,这样我们就完成了add方法
接着还有查看订单操作,查看订单,会根据用户的role去显示出不同的订单。如果role=admin 它查询出所有的订单,如果role=user 它只查询出当前用户的订单,这个功能的实现是在用户添加完订单订单成功后,会显示查看订单操作。<a href="${pageContext.request.contextPath}/order method=search">


现在我们开始写service,还是先写接口:
package cn.itcast.estore.service;

import java.sql.SQLException;
import java.util.List;

import cn.itcast.estore.annotation.PrivilegeInfo;
import cn.itcast.estore.domain.Order;
import cn.itcast.estore.domain.User;
import cn.itcast.estore.exception.PrivilegeException;

public interface OrderService {

	// 添加订单
	@PrivilegeInfo("生成订单")
	public void add(User user, Order order) throws PrivilegeException,
			Exception;

	// 根据用户查找订单
	@PrivilegeInfo("查看订单")
	public List<Order> find(User user) throws PrivilegeException, Exception;

	// 根据id删除订单
	public void delete(String id) throws Exception;

	public void updateState(String id) throws Exception;
}


接着开始实现接口,并用到上面说的那些注意事项
package cn.itcast.estore.service;

import java.sql.SQLException;
import java.util.List;

import cn.itcast.estore.dao.OrderDao;
import cn.itcast.estore.dao.OrderItemDao;
import cn.itcast.estore.dao.ProductDao;
import cn.itcast.estore.domain.Order;
import cn.itcast.estore.domain.OrderItem;
import cn.itcast.estore.domain.User;
import cn.itcast.estore.exception.OrderException;
import cn.itcast.estore.exception.PrivilegeException;
import cn.itcast.estore.utils.DataSourceUtils;

public class OrderServiceImpl implements OrderService {
	// 添加订单
	public void add(User user, Order order) throws PrivilegeException {
		OrderDao dao = new OrderDao();
		OrderItemDao idao = new OrderItemDao();
		ProductDao pdao = new ProductDao();

		try {

			// 开启事务
			DataSourceUtils.startTransaction();
			// 1.向orders表中添加数据
			dao.createOrder(order);
			// 2.向orderitem表中添加数据
			idao.addOrderItem(order);
			// 3.修改products表中数据
			pdao.updateProductCount(order);
		} catch (SQLException e) {
			e.printStackTrace();
			try {
				DataSourceUtils.rollback(); // 事务回滚
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} finally {
			try {
				DataSourceUtils.commitAndReleased(); // 事务提交与释放
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

	// 根据用户查找订单
	public List<Order> find(User user) throws PrivilegeException, SQLException {

		List<Order> orders = new OrderDao().findOrder(user); // 查询订单信息,不包含订单中的商品信息

		OrderItemDao idao = new OrderItemDao();

		// 根据得到的订单,查询订单中商品信息.
		for (Order order : orders) {

			List<OrderItem> items = idao.findOrderItemByOrderId(order);

			order.setOrderItems(items);

		}

		return orders;
	}

	// 根据id删除订单
	public void delete(String id) throws OrderException {

		OrderDao dao = new OrderDao();
		OrderItemDao idao = new OrderItemDao();
		ProductDao pdao = new ProductDao();
		// 1.修改商品表中商品数量

		try {
			DataSourceUtils.startTransaction(); //开启事务
			// 1.1 得到商品的数量
			List<OrderItem> items = idao.findOrderItemByOrderId(id);
			// 1.2修改商品的数量
			pdao.updateProductCount(items);
			// 2.删除订单项
			idao.delOrderItem(id);
			// 3.删除订单
			dao.delOrder(id);

		} catch (SQLException e) {
			e.printStackTrace();

			try {
				DataSourceUtils.rollback(); //事务回滚
			} catch (SQLException e1) {
				e1.printStackTrace();
			}

			throw new OrderException("删除订单失败");

		} finally {
			try {
				DataSourceUtils.commitAndReleased(); //事务提交
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

	}

	// 根据订单号修改订单状态
	public void updateState(String id) throws SQLException {
		OrderDao dao = new OrderDao();

		dao.updateState(id);
	}

}


最后我们开始写Servlet,因为admin可以查看所有用户的订单,而用户只可以查看自己的订单,所以在这需要一个factory实例化一下对象
package cn.itcast.estore.web.servlet;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import cn.itcast.estore.domain.Order;
import cn.itcast.estore.domain.OrderItem;
import cn.itcast.estore.domain.Product;
import cn.itcast.estore.domain.User;
import cn.itcast.estore.exception.OrderException;
import cn.itcast.estore.factory.OrderServiceFactory;
import cn.itcast.estore.service.OrderService;

/**
 * Servlet implementation class OrderServlet
 */
public class OrderServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public OrderServlet() {
		super();
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.getWriter().append("Served at: ").append(request.getContextPath());
		String method = request.getParameter("method");

		if ("add".equals(method)) {
			add(request, response);
		} else if ("del".equals(method)) {
			del(request, response);
		} else if ("search".equals(method)) {
			search(request, response);
		}

	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

	public void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 1.将请求参数封装到Order对象中.
		Order order = new Order();
		// 1.1 表单数据
		try {
			BeanUtils.populate(order, request.getParameterMap()); // 只封装了表单数据到javaBean,简单说,只有receiverinfo
																	// money两项
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}

		// 1.2 订单编号 当前用户id
		order.setId(UUID.randomUUID().toString());

		User user = (User) request.getSession().getAttribute("user");
		if (user == null) {
			response.sendRedirect(request.getContextPath() + "/error/error.jsp");
			return;
		}
		order.setUser_id(user.getId());

		// 1.3 将订单项封装到订单中.
		Map<Product, Integer> cart = (Map<Product, Integer>) request.getSession().getAttribute("cart"); // 得到购物车
		List<OrderItem> items = new ArrayList<OrderItem>();
		for (Product p : cart.keySet()) {

			OrderItem item = new OrderItem();

			item.setOrder_id(order.getId());
			item.setProduct_id(p.getId());
			item.setBuynum(cart.get(p));
			items.add(item);
		}

		order.setOrderItems(items);

		// 2.调用OrderService中方法,创建订单
		OrderService service = OrderServiceFactory.getInstance();

		try {
			service.add(user, order);
			response.getWriter().write("下单成功,<a href='" + request.getContextPath() + "/index.jsp'>继续购物</a>,<a href='"
					+ request.getContextPath() + "/order?method=search'>查看订单</a>");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public void del(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id"); // 得到要删除的订单的id。

		// 调用OrderService中删除订单操作
		OrderService service = OrderServiceFactory.getInstance();

		try {
			service.delete(id);

			// 在次查询订单
			response.sendRedirect(request.getContextPath() + "/order?method=search");
			return;
		} catch (OrderException e) {
			e.printStackTrace();
			response.getWriter().write(e.getMessage());
			return;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void search(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 1.得到当前用户
		User user = (User) request.getSession().getAttribute("user");

		if (user == null) {
			response.getWriter().write("请先<a href='" + request.getContextPath() + "/index.jsp'>登录</a>");
			return;
		}

		// 2.调用OrderService中查询订单操作
		OrderService service = OrderServiceFactory.getInstance();

		try {
			List<Order> orders = service.find(user);

			request.setAttribute("orders", orders);

			request.getRequestDispatcher("/showOrder.jsp").forward(request, response);

		} catch (SQLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
这样我们就完成了目前来说最难的Order模块设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值