数据库表分析

我们先来看下tb_order表,如下图所示。 
 
可以看到:

  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表中,主键id字段也是个字符串,我们也需要为其生成主键,不过我倒是觉得,如果id用Long类型并且主键自增长会更好点,如下图所示。 
 
接着我们看tb_order_shipping,这张表存放的是用户的收货信息,包括收货人姓名、固定电话、移动电话、省、市、区/县、街道门牌号、邮政编码,而且收货人信息与订单是一对一的关系,因此收货地址表的主键是order_id。 

订单生成页面分析

生成订单是在订单确认页面进行的,如下图所示,可以看到”提交订单”按钮。 
 
我们找到这个页面对应的jsp文件,那就是order-cart.jsp,搜索”提交订单”,可以看到如下图所示搜索结果,可以看到这是个button按钮,该按钮的onclick事件中使用id选择器来得到表单,并且将该表单提交。 
 
那么,表单在哪儿呢?我们搜索”orderForm”,如下图所示,可以看到这个表单所有的标签都是隐藏的,是不会被用户看到的,用户看到的只是表单下面展示的信息(这些信息只是做展示用,不会被提交,真正提交的是被隐藏的表单)。表单要提交的话,我们一般用pojo来接收比较合适,那么这个表单我们应该用什么样的pojo来接收呢? 
 
我们分析下上图的表单,这个表单中包含了三张表的信息,其中<input type="hidden" name="paymentType" value="1"/>便是tb_order表中的付款类型字段,这里默认是1了,<c:forEach>标签遍历的是购物车列表,var="cart"表示单个购物车对象,varStatus="status"的用法如下所示:

  • varStatus属性可以方便我们实现一些与行数相关的功能,如:奇数行、偶数行差异;最后一行特殊处理等等。先就varStatus属性常用参数总结下:

    1. ${status.index}:输出行号,从0开始。
    2. ${status.count}:输出行号,从1开始。
    3. ${status.current}:当前这次迭代的(集合中的)项。
    4. ${status.first}:判断当前项是否为集合中的第一项,返回值为true或false。
    5. ${status.last}:判断当前项是否为集合中的最后一项,返回值为true或false。
    6. begin、end、step分别表示:起始序号,结束序号,跳跃步伐。

可以看到我们这里用到的便是其行号功能,而且是从0开始,orderItems是个集合,该集合通过索引号获取它的对象,然后将购物车对象的对应属性赋给orderItems集合中当前索引号下的对象的这个属性,totalPrice是将购物车里每款商品的总价格相加,就是整个订单的总金额。<c:forEach>标签里面的属性值都是tb_order_item表中的字段。<c:forEach>标签之后就是payment字段,该字段也是tb_order表里面的字段,表示付款金额,我们看到了给payment赋的值是value=”${totalPrice/100 }”,这里之所以要除100是由于我们的tb_order_item表中定义的商品单价便是整数,这个整数是以分为单位乘以100的,这样两位小数的金额比如11.11元便在数据库表中存成了1111,当然了,数据库表中存储的金额单位便是分了,不再是元了。数据库表中虽然存储的是以分为单位的价格,但是我们展示在页面的价格肯定是以元为单位的,因此我们需要让totalPrice/100,这才是以元为单位的金额。接着,下面这几句代码意思比较明显,显然存放的是收货人地址信息,用到的类是逆向生成的TbOrderShipping类。

<input type="hidden" name="orderShipping.receiverName" value="入云龙"/>
<input type="hidden" name="orderShipping.receiverMobile" value="15891588888"/>
<input type="hidden" name="orderShipping.receiverState" value="北京"/>
<input type="hidden" name="orderShipping.receiverCity" value="北京"/>
<input type="hidden" name="orderShipping.receiverDistrict" value="昌平区"/>
<input type="hidden" name="orderShipping.receiverAddress" value="西三旗 xxxxxxxxx"/>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

综合以上情况,我们来写个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在网络中传输,我们需要让它实现序列化接口。 
 
为了方便大家复制,现将OrderInfo类的代码给出。

public class OrderInfo extends TbOrder implements Serializable {// 商品列表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;}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

生成订单服务层

首先我们需要在taotao-order-interface工程中新建一个接口并在该接口中添加一个方法,如下图所示。 
 
紧接着我们在taotao-order-service工程的com.taotao.order.service.impl包下新建OrderService接口的实现类,如下图所示。 
 
为方便大家复制,现将OrderServiceImpl实现类的代码给出。

/*** 订单处理Service* <p>Title: OrderServiceImpl</p>* <p>Description: </p>* <p>Company: www.itcast.cn</p> * @version 1.0*/
@Service
public class OrderServiceImpl implements OrderService {@Autowiredprivate TbOrderMapper orderMapper;@Autowiredprivate TbOrderItemMapper orderItemMapper;@Autowiredprivate TbOrderShippingMapper orderShippingMapper;@Autowiredprivate JedisClient jedisClient;@Value("${ORDER_GEN_KEY}")private String ORDER_GEN_KEY;@Value("${ORDER_ID_INIT}")private String ORDER_ID_INIT;@Value("${ORDER_DETAIL_GEN_KEY}")private String ORDER_DETAIL_GEN_KEY;@Overridepublic TaotaoResult createOrder(OrderInfo orderInfo) {// 生成一个订单号,使用Redis的incr命令来生成// ORDER_GEN_KEY就是对应订单号生成的key// 判断订单号生成的key是否存在if (!jedisClient.exists(ORDER_GEN_KEY)) {// 如果不存在,要设置初始值jedisClient.set(ORDER_GEN_KEY, ORDER_ID_INIT);}String orderId = jedisClient.incr(ORDER_GEN_KEY).toString();// 向订单表插入数据orderInfo.setOrderId(orderId);// 免邮费orderInfo.setPostFee("0");// 订单状态// 状态:1、未付款,2、已付款,3、未发货,4、已发货,5、交易成功,6、交易关闭orderInfo.setStatus(1);Date date = new Date();orderInfo.setCreateTime(date);orderInfo.setUpdateTime(date);// 插入数据orderMapper.insert(orderInfo);// 向订单明细表插入数据List<TbOrderItem> orderItems = orderInfo.getOrderItems();for (TbOrderItem tbOrderItem : orderItems) {// 生成一个订单明细表的主键Long orderDetailId = jedisClient.incr(ORDER_DETAIL_GEN_KEY);tbOrderItem.setId(orderDetailId.toString());// 设置订单idtbOrderItem.setOrderId(orderId);// 插入数据orderItemMapper.insert(tbOrderItem);}// 向订单物流信息表插入数据TbOrderShipping orderShipping = orderInfo.getOrderShipping();orderShipping.setOrderId(orderId);orderShipping.setCreated(date);orderShipping.setUpdated(date);orderShippingMapper.insert(orderShipping);// 返回订单号return TaotaoResult.ok(orderId);}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

注意:向tb_order中插入记录时,我们是使用Redis的incr命令生成的订单号,而且该订单号还应有一个初始值。ORDER_GEN_KEY常量就是对应订单号生成的key,假如说这个key在Redis中不存在的话会有什么后果?如果原来这个key没有,你直接调用incr这个命令那么就会创建这个key,它是从1开始的序列,咱们刚才说了这个订单号最好应该有一个初始值,要不太小的话,别人一看一共就没卖出几单去,别人就没有购买的欲望了,所以给一个初始值比较好。 
OrderServiceImpl实现类的代码中用到了常量,我们把常量放到配置文件中,如下图所示。 
 
配置文件有了,但是我们要确认Spring容器加载了该配置文件,我们查看applicationContext-dao.xml文件,发现加载了properties目录下所有以.properties文件结尾的配置文件。所以自然而然resource.properties文件也被加载了。 

订单生成表现层

既然服务端的代码写好了,我们便要发布服务,我们在applicationContext-service.xml文件中发布,如下图所示。 
 
发布服务的代码如下:

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

下面便是在taotao-order-web工程中引用dubbo服务,如下图所示。 
 
引用服务的代码如下:

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

接着我们在taotao-order-web工程的OrderController类中添加一个方法,如下图所示,其中用到了3天以后的时间,以前我们用Calandar来计算日期,但太麻烦了,这里介绍一个简单的方法,那就是使用joda-time-2.5.jar这个包,实例化DateTime,然后直接使用plusDays(3)方法便可以得到3天后的日期,是不是非常方便。订单生成成功后,我们要跳转到订单生成成功页面,这个页面是success.jsp,这个页面有三个变量需要从Controller传过来,因此我们便在Controller方法中使用Model带回这三个参数。 
 
为方便大家复制,现将OrderController类中createOrder方法的代码给出。

@RequestMapping(value="/order/create", method=RequestMethod.POST)
public String createOrder(OrderInfo orderInfo, Model model, HttpServletRequest request) {// 取用户idTbUser user = (TbUser) request.getAttribute("user");orderInfo.setUserId(user.getId());orderInfo.setBuyerNick(user.getUsername());// 调用服务生成订单TaotaoResult result = orderService.createOrder(orderInfo);// 取订单号并传递给页面String orderId = result.getData().toString();model.addAttribute("orderId", orderId);model.addAttribute("payment", orderInfo.getPayment());// 预计送达时间是三天后DateTime dateTime = new DateTime();dateTime = dateTime.plusDays(3);model.addAttribute("date", dateTime.toString("yyyy-MM-dd"));// 返回逻辑视图return "success";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

@RequestMapping("/order/create")注解中的请求来自于taotao-order-web工程的order-cart.jsp页面中的隐藏表单,如下图所示。 

测试

代码终于写完了,下面我们便来测试,我们先将taotao-order工程打包到本地maven仓库,然后用tomcat插件启动taotao-order工程(这个我已经写过太多遍了,就不再写了),然后再重启taotao-order-web工程。 
当我们点击下图所示的”提交订单”按钮后。 
 
便会生成一个订单,如下图所示。 
 
并且数据库中tb_order、tb_order_item以及tb_order_shipping这三张表已经插入数据了,这儿就不截图了,读者如若不信,可亲测。

至此,生成订单功能圆满完成!!!

转载博客:http://blog.csdn.net/yerenyuan_pku/article/details/73430922

淘淘商城--生成订单相关推荐

  1. 淘淘商城——生成订单

    本文我们将一起学习下如何生成订单. 数据库表分析 我们先来看下tb_order表,如下图所示. 可以看到: 主键order_id是字符串类型,不是自增长的,因此我们需要自己生成订单编号,我们平时使用京 ...

  2. 淘淘商城第113讲——生成订单

    本讲我们将一起学习下如何生成订单. 数据库表设计分析 订单表 我们先来看下tb_order表的结构,如下图所示. 可以看到: 从订单表的结构中还可以看到create_time.buyer_nick.s ...

  3. 黑马淘淘商城第十二天 购物车实现、订单确认页面展示

    1. 课程计划 第十二天: 1.购物车实现 2.订单确认页面展示 2. 购物车的实现 2.1. 功能分析 1.购物车是一个独立的表现层工程. 2.添加购物车不要求登录.可以指定购买商品的数量. 3.展 ...

  4. 淘淘商城第111讲——订单系统服务层和表现层工程搭建

    首先我们还是先看一眼淘淘商城的系统架构,如下图所示,可以看到订单系统是一个单独的模块,分服务层和表现层,服务层负责存储订单,表现层负责展示订单. 下面我们便要开始搭建工程了,可以先搭建订单系统的服务层 ...

  5. ssm(Spring、Springmvc、Mybatis)实战之淘淘商城-第四天(非原创)

    文章大纲 一.课程介绍 二.今日内容介绍 三.参考资料下载 四.参考文章 一.课程介绍 一共14天课程 (1)第一天:电商行业的背景.淘淘商城的介绍.搭建项目工程.Svn的使用. (2)第二天:框架的 ...

  6. 淘淘商城分布式电商系统项目总结

    淘淘商城是采用分布式架构部署的一个大型网上商城系统,类似于京东商城.本系统分前台系统和后台系统.前台系统主要负责商城的页面的显示功能,这里采用的面向服务的方式,pc端手机端只负责显示页面,业务逻辑都在 ...

  7. SSM分布式项目之淘淘商城-第一天(IDEA)

    文章大纲 一.第一天课程计划 二.电商行业介绍 三.淘淘商城系统功能 四.系统架构 五.技术选型和开发环境 六.工程搭建 七.代码实现 八.参考文章 淘淘商城课程大纲 课程大纲 一共14天课程 (1) ...

  8. SSM分布式项目之淘淘商城-第二天(IDEA)

    文章大纲 一.第二天课程计划 二.功能分析 三.Dubbo 四.框架整合 五.dubbo配置测试 六.商品列表查询 七.Dubbo监控中心 八.参考文章 淘淘商城课程大纲 课程大纲 一共14天课程 ( ...

  9. SpringBoot+Docker重构淘淘商城

    本项目源于某培训机构的宜立方商城(淘淘商城)项目,重新利用 SpringBoot 2.0.4 框架替代原始的SSM三大框架进行重构项目,采用 Docker 容器替代原本的虚拟机来进行项目的部署. 利用 ...

最新文章

  1. 二逼平衡树——树套树(线段树套Splay平衡树)
  2. 程序员编程时戴耳机是在听什么?
  3. 无人驾驶急需解决:规划控制和传感器价格高两大问题
  4. [云炬ThinkPython阅读笔记]第一章 程序之道
  5. C#委托的异步调用[转]
  6. 22543!Windows 11 新预览版发布
  7. 阿里P8亲自教你!mysql列转行
  8. 转:防止跨站攻击,安全过滤
  9. THINKPHP3.2视频教程
  10. stm32运行linux,新出的STM32F750成功运行Linux
  11. JAVA中注解controller_SpringMVC之基于注解的Controller
  12. Makefile、.mk、.bp、Blueprint、Soong、kati工具链的关系
  13. linux:账号管理
  14. yum在linux安装mysql数据库_linux安装mysql(yum安装,比较简单)
  15. 《穿越计算机的迷雾》读书笔记六
  16. python去重drop_duplicates后一定要reset_index()
  17. 小学计算机课程目录五年级,小学信息技术课程目录.doc
  18. 有道云笔记 迁移 语雀过程记录
  19. [已解决] Could not create connection to database server.
  20. MTK6577+Android启动----pre-loader

热门文章

  1. 真智能还是伪智能?谈谈人工智能在企业SaaS中的应用之HR篇
  2. CCS6.2.0 报错: ROM_ADCIntClear等是 unresolved symbols remain
  3. Cinder-Volume如何实现AA高可用——分布式锁以及在Openstack上的应用
  4. AI人工智能在2020年的7个发展趋势
  5. Win7下C:\Users\Cortana以账户名称命名的系统文件夹用户名的修改
  6. #今日论文推荐# 光子神经网络登上nature,图像识别速度降至1纳秒
  7. 优化与求解非线性方程组(单变量问题)
  8. 通俗傻瓜式理清光栅化渲染和光线追踪渲染的原理
  9. Postfix 发送邮件失败问题,求大神
  10. C++ 火柴棍摆正方形