[TOC]
## 步骤 1 : 先运行,看到效果,再学习
先将完整的 spring 项目(向老师要相关资料),配置运行起来,确认可用之后,再学习做了哪些步骤以达到这样的效果。
## 步骤 2 : 模仿和排错
在确保可运行项目能够正确无误地运行之后,再严格照着教程的步骤,对代码模仿一遍。
模仿过程难免代码有出入,导致无法得到期望的运行结果,此时此刻通过比较**正确答案** ( 可运行项目 ) 和自己的代码,来定位问题所在。
采用这种方式,**学习有效果,排错有效率**,可以较为明显地提升学习速度,跨过学习路上的各个槛。
## 步骤 3 : 准备数据SQL
订单数据,以及其对应的订单项数据,都是由前台功能增加的。
为了在后台演示效果,需要自己在数据库中插入数据
1. 订单:
```
insert into t_order (order_code, address, post, receiver, mobile, user_message,
create_date, pay_date, delivery_date, confirm_date, status, user_id)
VALUES ('201608241638122609867','某某市,某某区,某某街道,某某号 ','610000','某某某','15111111111',NULL,'2018-08-30',NULL,NULL,NULL,'waitDelivery',6);
```
注: 倒数第二个参数6是对应的用户id,需要在数据库中存在,请根据自己的数据信息自行修改。
2. 订单项
```
insert into t_order_item (number, user_id, product_id, order_id)
VALUES (2,6,1,1);
insert into t_order_item (number, user_id, product_id, order_id)
VALUES (3,6,2,1);
```
注: 第三个参数1、2分别对应的产品id,需要在数据库中存在,请根据自己的数据信息自行修改。
## 步骤 4 : 页面截图
![](https://box.kancloud.cn/1920f2555e356f3dddf17625ff454fa4_1847x449.png)
## 步骤 5 : OrderItem
OrderItem在自动创建的基础上增加了一个product属性。 因为在订单管理页面需要看到订单下面的订单项里的产品图片。
```
package com.dodoke.tmall.pojo;
public class OrderItem {
private Integer id;
private Integer number;
private Integer userId;
private Integer productId;
private Integer orderId;
/* 非数据库字段 */
private Product product;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
```
## 步骤 6 : Order.java
Order类在自动生成的基础上,新增4个字段:
1. 该订单下的订单项列表
`private List<OrderItem> orderItems;`
2. 该订单对应的用户
` private User user;`
3. 该订单的总计金额
`private float total;`
4 该订单的总计数量
`private int totalNumber;`
除此之外,还提供了一个getStatusDesc方法,用于把英文表达的Status信息转换为中文:
```
package com.dodoke.tmall.pojo;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import com.dodoke.tmall.service.OrderService;
public class Order {
private Integer id;
private String orderCode;
private String address;
private String post;
private String receiver;
private String mobile;
private String userMessage;
private Date createDate;
private Date payDate;
private Date deliveryDate;
private Date confirmDate;
private String status;
private Integer userId;
/* 如下是非数据库字段 */
private List<OrderItem> orderItems;
private User user;
private float total;
private int totalNumber;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getOrderCode() {
return orderCode;
}
public void setOrderCode(String orderCode) {
this.orderCode = orderCode == null ? null : orderCode.trim();
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address == null ? null : address.trim();
}
public String getPost() {
return post;
}
public void setPost(String post) {
this.post = post == null ? null : post.trim();
}
public String getReceiver() {
return receiver;
}
public void setReceiver(String receiver) {
this.receiver = receiver == null ? null : receiver.trim();
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile == null ? null : mobile.trim();
}
public String getUserMessage() {
return userMessage;
}
public void setUserMessage(String userMessage) {
this.userMessage = userMessage == null ? null : userMessage.trim();
}
public String getCreateDate() {
String createDateFormat = null;
if (null != createDate) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
createDateFormat = simpleDateFormat.format(createDate);
}
return createDateFormat;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public String getPayDate() {
String payDateFormat = null;
if (null != payDate) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
payDateFormat = simpleDateFormat.format(payDate);
}
return payDateFormat;
}
public void setPayDate(Date payDate) {
this.payDate = payDate;
}
public String getDeliveryDate() {
String deliveryDateFormat = null;
if (null != deliveryDate) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
deliveryDateFormat = simpleDateFormat.format(deliveryDate);
}
return deliveryDateFormat;
}
public void setDeliveryDate(Date deliveryDate) {
this.deliveryDate = deliveryDate;
}
public String getConfirmDate() {
String confirmDateFormat = null;
if (null != confirmDate) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
confirmDateFormat = simpleDateFormat.format(confirmDate);
}
return confirmDateFormat;
}
public void setConfirmDate(Date confirmDate) {
this.confirmDate = confirmDate;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status == null ? null : status.trim();
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public List<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(List<OrderItem> orderItems) {
this.orderItems = orderItems;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getTotal() {
DecimalFormat decimalFormat=new DecimalFormat(".00");//构造方法的字符格式这里如果小数不足2位,会以0补足.
return decimalFormat.format(total);
}
public void setTotal(float total) {
this.total = total;
}
public int getTotalNumber() {
return totalNumber;
}
public void setTotalNumber(int totalNumber) {
this.totalNumber = totalNumber;
}
public static void main(String args[]) {
Order o = new Order();
o.setStatus(OrderService.delete);
System.out.println(o.getStatusDesc());
}
public String getStatusDesc() {
String desc = "未知";
switch (status) {
case OrderService.waitPay:
desc = "待付款";
break;
case OrderService.waitDelivery:
desc = "待发货";
break;
case OrderService.waitConfirm:
desc = "待收货";
break;
case OrderService.waitReview:
desc = "等评价";
break;
case OrderService.finish:
desc = "完成";
break;
case OrderService.delete:
desc = "刪除";
break;
default:
desc = "未知";
}
return desc;
}
}
```
## 步骤 7 : OrderItemService
新建OrderItemService,声明CRUD一套,以及`fill(Order order) `和`fill(List<Order> orders) `, 这两个方法有什么用呢? 将在下个步骤OrderItemServiceImpl里讲解。
```
package com.dodoke.tmall.service;
import java.util.List;
import com.dodoke.tmall.pojo.Order;
import com.dodoke.tmall.pojo.OrderItem;
public interface OrderItemService {
void add(OrderItem c);
void delete(int id);
void update(OrderItem c);
OrderItem get(int id);
List list();
void fill(List<Order> os);
void fill(Order o);
}
```
## 步骤 8 : OrderItemServiceImpl
OrderItemServiceImpl实现OrderItemService,提供CRUD一套方法的实现。
同时还提供`fill(Order order)`和`fill(List<Order> orders)`,
先说`fill(Order order) `:
为什么要提供这个方法呢? 因为在订单管理界面,首先是遍历多个订单,然后遍历这个订单下的多个订单项。 而由MybatisGenerator逆向工程所创建的一套自动生成代码,是不具备一对多关系的,需要自己去二次开发。 这里就是做订单与订单项的一对多关系。
在`fill(Order order)`中:
1. 根据订单id查询出其对应的所有订单项
2. 通过setProduct为所有的订单项设置Product属性
3. 遍历所有的订单项,然后计算出该订单的总金额和总数量
4. 最后再把订单项设置在订单的orderItems属性上。
在`fill(List<Order> orders)` 中,就是遍历每个订单,然后挨个调用`fill(Order order)`。
```
package com.dodoke.tmall.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dodoke.tmall.mapper.OrderItemMapper;
import com.dodoke.tmall.pojo.Order;
import com.dodoke.tmall.pojo.OrderItem;
import com.dodoke.tmall.pojo.OrderItemExample;
import com.dodoke.tmall.pojo.Product;
import com.dodoke.tmall.service.OrderItemService;
import com.dodoke.tmall.service.ProductService;
@Service
public class OrderItemServiceImpl implements OrderItemService {
@Autowired
OrderItemMapper orderItemMapper;
@Autowired
ProductService productService;
@Override
public void add(OrderItem c) {
orderItemMapper.insert(c);
}
@Override
public void delete(int id) {
orderItemMapper.deleteByPrimaryKey(id);
}
@Override
public void update(OrderItem c) {
orderItemMapper.updateByPrimaryKeySelective(c);
}
@Override
public OrderItem get(int id) {
OrderItem result = orderItemMapper.selectByPrimaryKey(id);
setProduct(result);
return result;
}
public List<OrderItem> list() {
OrderItemExample example = new OrderItemExample();
example.setOrderByClause("id desc");
return orderItemMapper.selectByExample(example);
}
@Override
public void fill(List<Order> os) {
// 遍历每个订单,然后挨个调用fill(Order order)。
for (Order o : os) {
fill(o);
}
}
public void fill(Order o) {
// 1. 根据订单id查询出其对应的所有订单项
OrderItemExample example = new OrderItemExample();
example.createCriteria().andOrderIdEqualTo(o.getId());
example.setOrderByClause("id desc");
List<OrderItem> ois = orderItemMapper.selectByExample(example);
// 2. 通过setProduct为所有的订单项设置Product属性
setProduct(ois);
float total = 0;
int totalNumber = 0;
// 3. 遍历所有的订单项,然后计算出该订单的总金额和总数量
for (OrderItem oi : ois) {
total += oi.getNumber() * oi.getProduct().getPromotePrice();
totalNumber += oi.getNumber();
}
o.setTotal(total);
o.setTotalNumber(totalNumber);
// 4. 最后再把订单项设置在订单的orderItems属性上。
o.setOrderItems(ois);
}
public void setProduct(List<OrderItem> ois) {
for (OrderItem oi : ois) {
setProduct(oi);
}
}
private void setProduct(OrderItem oi) {
Product p = productService.get(oi.getProductId());
oi.setProduct(p);
}
}
```
## 步骤 9 : OrderService
创建OrderService,提供CRUD一套,并提供订单状态的常量值。
```
package com.dodoke.tmall.service;
import java.util.List;
import com.dodoke.tmall.pojo.Order;
public interface OrderService {
String waitPay = "waitPay";
String waitDelivery = "waitDelivery";
String waitConfirm = "waitConfirm";
String waitReview = "waitReview";
String finish = "finish";
String delete = "delete";
void add(Order c);
void delete(int id);
void update(Order c);
Order get(int id);
List list();
}
```
## 步骤 10 : OrderServiceImpl
创建OrderServiceImpl ,实现CRUD一套方法
```
package com.dodoke.tmall.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dodoke.tmall.mapper.OrderMapper;
import com.dodoke.tmall.pojo.Order;
import com.dodoke.tmall.pojo.OrderExample;
import com.dodoke.tmall.pojo.User;
import com.dodoke.tmall.service.OrderService;
import com.dodoke.tmall.service.UserService;
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
OrderMapper orderMapper;
@Autowired
UserService userService;
@Override
public void add(Order c) {
orderMapper.insert(c);
}
@Override
public void delete(int id) {
orderMapper.deleteByPrimaryKey(id);
}
@Override
public void update(Order c) {
orderMapper.updateByPrimaryKeySelective(c);
}
@Override
public Order get(int id) {
return orderMapper.selectByPrimaryKey(id);
}
public List<Order> list() {
OrderExample example = new OrderExample();
example.setOrderByClause("id desc");
List<Order> result = orderMapper.selectByExample(example);
setUser(result);
return result;
}
public void setUser(List<Order> os) {
for (Order o : os) {
setUser(o);
}
}
public void setUser(Order o) {
int uid = o.getUserId();
User u = userService.get(uid);
o.setUser(u);
}
}
```
## 步骤 11 : OrderController.java
因为订单的增加和删除,都是在前台进行的。 所以OrderController提供的是list方法和`delivery(发货)`方法
```
package com.dodoke.tmall.controller;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.dodoke.tmall.pojo.Order;
import com.dodoke.tmall.service.OrderItemService;
import com.dodoke.tmall.service.OrderService;
import com.dodoke.tmall.util.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@Controller
@RequestMapping("")
public class OrderController {
@Autowired
OrderService orderService;
@Autowired
OrderItemService orderItemService;
/**
* 分页查询
* @param model 模型
* @param page 页面对象
* @return 集合
*/
@RequestMapping("admin_order_list")
public String list(Model model, Page page) {
PageHelper.offsetPage(page.getStart(), page.getCount());
List<Order> os = orderService.list();
int total = (int) new PageInfo<>(os).getTotal();
page.setTotal(total);
orderItemService.fill(os);
model.addAttribute("os", os);
model.addAttribute("page", page);
return "admin/listOrder";
}
/**
* 发货
* @param o 订单对象
* @return 页面路径
* @throws IOException
*/
@RequestMapping("admin_order_delivery")
public String delivery(Order o) throws IOException {
o.setDeliveryDate(new Date());
o.setStatus(OrderService.waitConfirm);
orderService.update(o);
return "redirect:admin_order_list";
}
}
```
## 步骤 12 : listOrder.jsp
增加listOrder.jsp。
## 步骤 13 : 查询功能讲解
访问地址:
`http://127.0.0.1:8080/tmall_ssm/admin_order_list`
即可看到订单查询界面。
`admin_order_list `导致`OrderController.list()`方法被调用
1. 获取分页对象
2. 查询订单集合
3. 获取订单总数并设置在分页对象上
4. 借助`orderItemService.fill()`方法为这些订单填充上orderItems信息
5. 把订单集合和分页对象设置在model上
6. 服务端跳转到`admin/listOrder.jsp`页面
7. 在`listOrder.jsp`借助`c:forEach`把订单集合遍历出来
8. 遍历订单的时候,再把当前订单的orderItem订单项集合遍历出来
![](https://box.kancloud.cn/9322c9792038da7743504b1882428187_1829x427.png)
OrderController:
```
/**
* 分页查询
* @param model 模型
* @param page 页面对象
* @return 集合
*/
@RequestMapping("admin_order_list")
public String list(Model model, Page page) {
PageHelper.offsetPage(page.getStart(), page.getCount());
List<Order> os = orderService.list();
int total = (int) new PageInfo<>(os).getTotal();
page.setTotal(total);
orderItemService.fill(os);
model.addAttribute("os", os);
model.addAttribute("page", page);
return "admin/listOrder";
}
```
listOrder.jsp:
```
<c:forEach items="${os}" var="o">
<tr>
<td>${o.id}</td>
<td>${o.statusDesc}</td>
<td>¥${o.total}</td>
<td align="center">${o.totalNumber}</td>
<td align="center">${o.user.name}</td>
<td>${o.createDate}</td>
<td>${o.payDate}</td>
<td>${o.deliveryDate}</td>
<td>${o.confirmDate}</td>
<td>
<button oid=${o.id} class="orderPageCheckOrderItems btn btn-primary btn-xs">查看详情</button>
<c:if test="${o.status=='waitDelivery'}">
<a href="admin_order_delivery?id=${o.id}">
<button class="btn btn-primary btn-xs">发货</button>
</a>
</c:if>
</td>
</tr>
<tr class="orderPageOrderItemTR" oid=${o.id}>
<td colspan="10" align="center">
<div class="orderPageOrderItem">
<table width="800px" align="center" class="orderPageOrderItemTable">
<c:forEach items="${o.orderItems}" var="oi">
<tr>
<td align="left">
<img width="40px" height="40px" src="img/productSingle/${oi.product.firstProductImage.id}.jpg">
</td>
<td>
<a href="foreproduct?pid=${oi.product.id}">
<span>${oi.product.name}</span>
</a>
</td>
<td align="right">
<span class="text-muted">${oi.number}个</span>
</td>
<td align="right">
<span class="text-muted">单价:¥${oi.product.promotePrice}</span>
</td>
</tr>
</c:forEach>
</table>
</div>
</td>
</tr>
</c:forEach>
```
## 步骤 14 : 发货功能讲解
当订单状态是waitDelivery的时候,就会出现发货按钮
1. 发货按钮链接跳转到`admin_order_delivery`
2. `OrderController.delivery()`方法被调用
2.1 注入订单对象
2.2 修改发货时间,设置发货状态
2.3 更新到数据库
2.4 客户端跳转到`admin_order_list`页面
![](https://box.kancloud.cn/ab60f562cb2c87c254e813797eada4f7_131x62.png)
```
/**
* 发货
* @param o 订单对象
* @return 页面路径
* @throws IOException
*/
@RequestMapping("admin_order_delivery")
public String delivery(Order o) throws IOException {
o.setDeliveryDate(new Date());
o.setStatus(OrderService.waitConfirm);
orderService.update(o);
return "redirect:admin_order_list";
}
```
## 步骤 15 : 增加,修改,删除功能
订单的增加和删除功能交由前台完成,后台不提供
- 项目简介
- 功能一览
- 前台
- 后台
- 开发流程
- 需求分析-展示
- 首页
- 产品页
- 分类页
- 搜索结果页
- 购物车查看页
- 结算页
- 确认支付页
- 支付成功页
- 我的订单页
- 确认收货页
- 确认收货成功页
- 评价页
- 需求分析-交互
- 分类页排序
- 立即购买
- 加入购物车
- 调整订单项数量
- 删除订单项
- 生成订单
- 订单页功能
- 确认付款
- 确认收货
- 提交评价信息
- 登录
- 注册
- 退出
- 搜索
- 前台需求列表
- 需求分析后台
- 分类管理
- 属性管理
- 产品管理
- 产品图片管理
- 产品属性设置
- 用户管理
- 订单管理
- 后台需求列表
- 表结构设计
- 数据建模
- 表与表之间的关系
- 后台-分类管理
- 可运行的项目
- 静态资源
- JSP包含关系
- 查询
- 分页
- 增加
- 删除
- 编辑
- 修改
- 做一遍
- 重构
- 分页方式
- 分类逆向工程
- 所有逆向工程
- 后台其他页面
- 属性管理实现
- 产品管理实现
- 产品图片管理实现
- 产品属性值设置
- 用户管理实现
- 订单管理实现
- 前端
- 前台-首页
- 可运行的项目
- 静态资源
- ForeController
- home方法
- home.jsp
- homePage.jsp
- 前台-无需登录
- 注册
- 登录
- 退出
- 产品页
- 模态登录
- 分类页
- 搜索
- 前台-需要登录
- 购物流程
- 立即购买
- 结算页面
- 加入购物车
- 查看购物车页面
- 登录状态拦截器
- 其他拦截器
- 购物车页面操作
- 订单状态图
- 生成订单
- 我的订单页
- 我的订单页操作
- 评价产品
- 总结