淘淘商城75-商城订单系统实现之生成订单

版权声明:本文为博主原创文章,如有转载请注明出处,谢谢。 https://blog.csdn.net/pdsu161530247/article/details/82312620

目录

1.功能展示

2.数据库表分析

3.前端如何传递三张表的数据

4.生成订单实现

4.1服务层

4.1.1dao层

4.1.2service层

4.2表现层

4.2.1引入服务

4.2.2controller

4.3测试访问


1.功能展示

用户在购物车点击去结算

点击提交订单

会创建一个订单

2.数据库表分析

在数据库中涉及到三张表

tb_order、tb_order_item、tb_order_shipping.

在tb_order表中

CREATE TABLE `tb_order` (
  `order_id` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '订单id',
  `payment` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '实付金额。精确到2位小数;单位:元。如:200.07,表示:200元7分',
  `payment_type` int(2) DEFAULT NULL COMMENT '支付类型,1、在线支付,2、货到付款',
  `post_fee` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '邮费。精确到2位小数;单位:元。如:200.07,表示:200元7分',
  `status` int(10) DEFAULT NULL COMMENT '状态:1、未付款,2、已付款,3、未发货,4、已发货,5、交易成功,6、交易关闭',
  `create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '订单更新时间',
  `payment_time` datetime DEFAULT NULL COMMENT '付款时间',
  `consign_time` datetime DEFAULT NULL COMMENT '发货时间',
  `end_time` datetime DEFAULT NULL COMMENT '交易完成时间',
  `close_time` datetime DEFAULT NULL COMMENT '交易关闭时间',
  `shipping_name` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流名称',
  `shipping_code` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流单号',
  `user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
  `buyer_message` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '买家留言',
  `buyer_nick` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '买家昵称',
  `buyer_rate` int(2) DEFAULT NULL COMMENT '买家是否已经评价',
  PRIMARY KEY (`order_id`),
  KEY `create_time` (`create_time`),
  KEY `buyer_nick` (`buyer_nick`),
  KEY `status` (`status`),
  KEY `payment_type` (`payment_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

可以看到: 

  1. 主键order_id是字符串类型,不是自增长的,因此我们需要自己生成订单编号,我们平时使用京东、天猫等购物网站,发现人家的订单号都是用数字组成的,我们也使用数字作为订单号,但是怎样才能使订单号不重复呢?用时间加随机数的方案生成的订单其实还是可能会重复的,当同一时刻生成的订单越多越有可能出现订单号一样的情况,因此我们不能使用这种方案。比较好的方案是什么呢?是用redis的incr方法,由于redis中每一个操作都是单线程的,所以每一个操作都是具有原子性的,因此不会出现编号重复的问题
  2. payment字段是实付金额,需要从前台传过来,保留小数点后2位。
  3. payment_type是支付类型,分为在线支付和货到付款,也需要从前台页面传过来。
  4. post_free字段是邮费,邮费得由前台传过来,因为很多电商都搞活动,买够多少钱的东西就免邮费,因此邮费是动态变化的。
  5. status字段是订单状态,订单状态我们暂且定义了6种状态,未付款、已付款、未发货、已发货、交易成功、交易关闭。
  6. create_time字段是订单创建时间,这没什么可说的。
  7. update_time字段是订单更新时间,这个通常是订单状态发生了变化。
  8. payment_time字段是付款时间。
  9. consign_time字段是发货时间。
  10. end_time字段是交易完成时间,这个通常是用户点确认收货的时间。
  11. close_time字段是交易关闭时间,交易关闭时间则是该订单的所有流程都走完后的时间。
  12. shipping_name字段是物流名称,即用的谁家的快递。
  13. shipping_code字段是物流单号,这个不用废话。
  14. user_id字段当然是指购买者ID。
  15. buyer_message字段是指买家留言。
  16. buyer_nick字段指买家昵称。
  17. buyer_rate字段记录买家是否已经评价。

表中还可以看到create_time、buyer_nick、status、payment_type这四个字段由key修饰,说明为这四个字段建立了索引。

在tb_order_item表中

CREATE TABLE `tb_order_item` (
  `id` varchar(20) COLLATE utf8_bin NOT NULL,
  `item_id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT '商品id',
  `order_id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT '订单id',
  `num` int(10) DEFAULT NULL COMMENT '商品购买数量',
  `title` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品标题',
  `price` bigint(50) DEFAULT NULL COMMENT '商品单价',
  `total_fee` bigint(50) DEFAULT NULL COMMENT '商品总金额',
  `pic_path` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品图片地址',
  PRIMARY KEY (`id`),
  KEY `item_id` (`item_id`),
  KEY `order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

从订单表中可以看到订单表中并没有购买商品详情信息,那么商品详情信息在哪儿存放呢?它被存放到了tb_order_item表中,主键id字段也是个字符串,我们也需要为其生成主键,同样使用redis的incr。

在tb_order_shipping表中

CREATE TABLE `tb_order_shipping` (
  `order_id` varchar(50) NOT NULL COMMENT '订单ID',
  `receiver_name` varchar(20) DEFAULT NULL COMMENT '收货人全名',
  `receiver_phone` varchar(20) DEFAULT NULL COMMENT '固定电话',
  `receiver_mobile` varchar(30) DEFAULT NULL COMMENT '移动电话',
  `receiver_state` varchar(10) DEFAULT NULL COMMENT '省份',
  `receiver_city` varchar(10) DEFAULT NULL COMMENT '城市',
  `receiver_district` varchar(20) DEFAULT NULL COMMENT '区/县',
  `receiver_address` varchar(200) DEFAULT NULL COMMENT '收货地址,如:xx路xx号',
  `receiver_zip` varchar(6) DEFAULT NULL COMMENT '邮政编码,如:310001',
  `created` datetime DEFAULT NULL,
  `updated` datetime DEFAULT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

这张表存放的是订单物流信息,包括收货人姓名、固定电话、移动电话、省、市、区/县、街道门牌号、邮政编码,而且收货人信息与订单是一对一的关系,因此收货地址表的主键是order_id。

3.前端如何传递三张表的数据

点击提交订单时,会触发$('#orderForm').submit()函数,使用id选择器来得到表单,并且将该表单提交。 

 那么,表单在哪儿呢?我们搜索"orderForm",如下图所示,可以看到这个表单所有的标签都是隐藏的,是不会被用户看到的,用户看到的只是表单下面展示的信息(这些信息只是做展示用,不会被提交,真正提交的是被隐藏的表单)。表单要提交的话,我们一般用pojo来接收比较合适,那么这个表单我们应该用什么样的pojo来接收呢?先来看看这个表单都有那些数据。

在这个表单中包含了tb_order、tb_order_item、tb_order_shipping三张表的数据,其中红色线框起来的支付方式paymentType、支付金额payment属于tb_order,黑色线框起来的商品信息属于tb_order_item,黄色线框起来的订单物流信息属于tb_order_shipping表。这里暂时将tb_order_shipping表的数据写死,支付方式也默认使用“1”。

综合以上情况,我们来写个pojo类包含这些表单信息,那么我们这个pojo应该放到哪儿比较合适呢?我们不能把它放到taotao-common当中,因为我们的taotao-order工程已经依赖了taotao-common工程了,如果taotao-common工程现在再依赖taotao-order,那么便成了相互依赖了,这是断不可行的。我们还想让它尽可能的共用,把它放到taotao-order-interface工程比较合适,因为taotao-order工程及taotao-order-web工程都依赖taotao-order-interface,因此把pojo写到taotao-order-interface工程比较合适。
          pojo类如下图所示,这里用到了一个技巧,那就是继承了TbOrder类,这样OrderInfo便直接拥有了TbOrder的属性。为了让该pojo在网络中传输,我们需要让它实现序列化接口。

package com.taotao.order.pojo;
 
import java.io.Serializable;
import java.util.List;
 
import com.taotao.pojo.TbOrder;
import com.taotao.pojo.TbOrderItem;
import com.taotao.pojo.TbOrderShipping;
 
public class OrderInfo extends TbOrder implements Serializable{
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	//订单商品表实体的集合
	private List<TbOrderItem> orderItems;
	//订单物流
	private TbOrderShipping orderShipping;
	
	public List<TbOrderItem> getOrderItems() {
		return orderItems;
	}
	public void setOrderItems(List<TbOrderItem> orderItems) {
		this.orderItems = orderItems;
	}
	public TbOrderShipping getOrderShipping() {
		return orderShipping;
	}
	public void setOrderShipping(TbOrderShipping orderShipping) {
		this.orderShipping = orderShipping;
	}
	
	
}

4.生成订单实现

既然表和接收表单的pojo都有了,代码就好写了。

4.1服务层

4.1.1dao层

直接使用逆向工程。

4.1.2service层

在taotao-order-interface创建接口

package com.taotao.order.service;
 
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.order.pojo.OrderInfo;
 
public interface OrderService {
	//生成订单,OrderInfo当中包含了表单提交的所有数据。
    TaotaoResult createOrder(OrderInfo orderInfo);
}

在taotao-order-service中

由于要操作redis所以需要jedis的依赖,在pom.xml中添加依赖

<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>

 代码中还用到了常量,我们把常量放到配置文件中,如下图所示。

#订单生成key
ORDER_ID_GEN_KEY=ORDER_ID_GEN
#订单号初始值
ORDER_ID_INIT_VALUE=100888
#订单明细表主键生成key
ORDER_ITEM_ID_GEN_KEY=ORDER_ITEM_ID_GEN

还需要添加properties文件扫描

创建com.taotao.order.service.impl包存放实现类

package com.taotao.order.service.impl;

import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;

import com.taotao.common.pojo.TaotaoResult;
import com.taotao.mapper.TbOrderMapper;
import com.taotao.mapper.TbOrderItemMapper;
import com.taotao.mapper.TbOrderShippingMapper;
import com.taotao.order.jedis.JedisClient;
import com.taotao.order.pojo.OrderInfo;
import com.taotao.order.service.OrderService;
import com.taotao.pojo.TbOrderItem;
import com.taotao.pojo.TbOrderShipping;

@Service
public class OrderServiceImpl implements OrderService {

	@Autowired
	private TbOrderMapper tbOrderMapper;
	@Autowired
	private TbOrderItemMapper tbOrderItemMapper;
	@Autowired
	private TbOrderShippingMapper tbOrderShippingMapper;
	@Autowired
	private JedisClient jedisClient;
	/** 订单表生成id的key */
	@Value("${ORDER_ID_GEN_KEY}")
	private String ORDER_ID_GEN_KEY;
	/** 订单表生成id的初始值 */
	@Value("${ORDER_ID_INIT_VALUE}")
	private String ORDER_ID_INIT_VALUE;
	/** 订单项表生成id的key */
	@Value("${ORDER_ITEM_ID_GEN_KEY}")
	private String ORDER_ITEM_ID_GEN_KEY;
	/** 发消息 */
	@Autowired
	private JmsTemplate jmsTemplate;
	@Resource(name = "topicDestination")
	private Destination topicDestination;

	/**
	 * 创建订单
	 */
	@Override
	public TaotaoResult createOrder(OrderInfo orderInfo) {
		// 1.插入订单表tb_order
		if (!jedisClient.exists(ORDER_ID_GEN_KEY)) {
			jedisClient.set(ORDER_ID_GEN_KEY, ORDER_ID_INIT_VALUE);
		}
		String orderId = jedisClient.incr(ORDER_ID_GEN_KEY).toString();
		// 补全orderInfo属性
		// 订单创建日期
		orderInfo.setCreateTime(new Date());
		// 订单编号
		orderInfo.setOrderId(orderId);
		// 订单邮费
		orderInfo.setPostFee("0");
		// 订单状态:1、未付款,2、已付款,3、未发货,4、已发货,5、交易成功,6、交易关闭
		orderInfo.setStatus(1);
		// 订单更新时间
		orderInfo.setUpdateTime(orderInfo.getCreateTime());
		// 在controller设置
		// info.setBuyerNick(buyerNick);买家昵称
		// info.setUserId(userId);用户id
		tbOrderMapper.insert(orderInfo);
		// 2.插入订单项表tb_order_item
		List<TbOrderItem> orderItems = orderInfo.getOrderItems();
		for (TbOrderItem tbOrderItem : orderItems) {	
			// 补全属性
			String orderItemId = jedisClient.incr(ORDER_ITEM_ID_GEN_KEY).toString();
			// 设置订单项id
			tbOrderItem.setId(orderItemId);
			// 设置订单项所属订单id
			tbOrderItem.setOrderId(orderId);
			tbOrderItemMapper.insert(tbOrderItem);
		}
		
		// 3.插入订单物流表tb_order_shipping
		TbOrderShipping orderShipping = orderInfo.getOrderShipping();
		// 补全属性
		// 设置订单物流表所属订单id
		orderShipping.setOrderId(orderId);
		orderShipping.setCreated(orderInfo.getCreateTime());
		orderShipping.setUpdated(orderInfo.getUpdateTime());
		tbOrderShippingMapper.insert(orderShipping);
		// 4.返回需要包含订单的ID
		return TaotaoResult.ok(orderId);
	}

}

在applicationContext-service.xml发布服务

<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.taotao.order.service.OrderService" ref="orderServiceImpl" timeout="300000"/>

4.2表现层

4.2.1引入服务

在springmvc.xml中引入服务

<dubbo:reference interface="com.taotao.order.service.OrderService" id="orderService"  timeout="300000"/>

4.2.2controller

请求的url:/order/create

参数:使用OrderInfo接收

返回值:逻辑视图。(页面应该显示订单号)

业务逻辑:

  1. 接收表单提交的数据OrderInfo。
  2. 补全用户信息。
  3. 调用Service创建订单。
  4. 返回逻辑视图展示成功页面
    1. 需要Service返回订单号
    2. 当前日期加三天。

/**
	 * 创建订单
	 * @param orderInfo
	 * @param request
	 * @return
	 */
	@RequestMapping(value="/order/create",method=RequestMethod.POST)
	public String createOrder(OrderInfo orderInfo,HttpServletRequest request) {
		//1.接收表单提交的OrderInfo
		//2.补全OrderInfo信息
		TbUser tbUser = (TbUser)request.getAttribute("USER_INFO");
		orderInfo.setUserId(tbUser.getId());
		orderInfo.setBuyerNick(tbUser.getUsername());
		//3.调用service创建订单
		TaotaoResult result = orderService.createOrder(orderInfo);
		//4.设置回显属性:orderId、payment、date
		request.setAttribute("orderId", result.getData());
		request.setAttribute("payment", orderInfo.getPayment());
		DateTime dateTime = new DateTime();
		DateTime plusDays = dateTime.plusDays(3);//加3天
		request.setAttribute("date", plusDays.toString("yyyy-MM-dd"));
		//5.返回逻辑视图展示成功页面
		return "success";
	}

4.3测试访问

安装taotao-order

启动

用户在购物车点击去结算

点击提交订单

会创建一个订单

数据库中已存在数据

本文参考:学习淘淘商城第一百零四课(生成订单)

猜你喜欢

转载自blog.csdn.net/pdsu161530247/article/details/82312620
今日推荐