Fork me on GitHub

十三.宜立方商城——订单系统

一.项目计划

  1. 订单系统实现
  2. 订单生成
  3. 数据库读写分离

二.订单系统

image

image

2.1 功能分析

1、在购物车页面点击“去结算”按钮跳转到订单确认页面。

  1. 必须要求用户登录
  2. 使用拦截器实现
  3. 如果用户未登录就跳转到登录界面
  4. 如果用户已经登录,放行。展示购物车页面
  5. 判断Cookie中是否有购物车数据
  6. 如果有同步到服务端

2、订单确认页面中选择收获地址,选择支付方式,确认商品列表

  1. 根据用户id查询收获地址列表
  2. 展示支付方式列表
  3. 从购物车中取商品列表,从服务端取购物车列表

3、订单确认页面点击”提交”,生成订单

4、展示订单生成完成,或者跳转到支付页面。

2.2 工程搭建

image

image

image

2.3 订单确认页面展示

image

image

image

image

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
/**
* @author RickYinPeng
* @ClassName OrderController
* @Description 订单管理Controller
* @date 2019/1/1/15:35
*/
public class OrderController {

@Autowired
private CartService cartService;

@RequestMapping("/order/order-cart")
public String showOrderCat(HttpServletRequest request){
//取用户id
TbUser user = (TbUser) request.getAttribute("user");

//根据用户id取收获地址列表
//使用静态数据

//取支付方式列表
//静态数据

//根据用户id取购物车列表
List<TbItem> cartList = cartService.getCartList(5L);

//把购物车列表传入jsp
request.setAttribute("cartList",cartList);

//返回逻辑视图
return "order-cat";
}
}

效果:
image

2.4 订单系统拦截器

image

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
/**
* @author RickYinPeng
* @ClassName LoginInterceptor
* @Description 用户登录拦截器
* @date 2019/1/1/16:49
*/
public class LoginInterceptor implements HandlerInterceptor{

@Value("${SSO_URL}")
private String SSO_URL;

@Autowired
private TokenService tokenService;

@Autowired
private CartService cartService;

@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
//从cookie中取token
String token = CookieUtils.getCookieValue(httpServletRequest, "token");

//判断token是否存在
if(StringUtils.isBlank("token")){
//如果token不存在,未登录状态,跳转到登录页面,用户登录成功后,跳转当前请求的url
//要做rediect跳转,这里不能forward,因为是不同的工程啊,我们要去SSO工程啊,只能重定向,不能转发
httpServletResponse.sendRedirect(SSO_URL+"/page/login?redirect="+httpServletRequest.getRequestURI());

//拦截
return false;
}
//如果token存在,调用sso系统的服务,根据token取用户信息
E3Result e3Result = tokenService.getUserByToken(token);

//如果取不到,用户登录已经过期,需要登录
if(e3Result.getStatus()!=200){

httpServletResponse.sendRedirect(SSO_URL+"/page/login?redirect="+httpServletRequest.getRequestURI());

return false;
}

//如果取到用户信息,是登录状态,需要将用户信息写入request中
TbUser tbUser = (TbUser) e3Result.getData();
httpServletRequest.setAttribute("user",tbUser);

//判断cookie中是否有购物车数据,如果有就合并到服务端
String jsonCartList = CookieUtils.getCookieValue(httpServletRequest, "cart", true);
if(StringUtils.isNotBlank(jsonCartList)){
//合并购物车
cartService.mergeCart(tbUser.getId(), JsonUtils.jsonToList(jsonCartList, TbItem.class));
}

//放行
return true;
}

@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

}

@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

}
}

拦截器配置:

1
2
3
4
5
6
7
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="yp.e3mall.order.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

我在未登录状态下,选了一个花花,然后点击去结算,然后让我跳到了登录状态,然后我登录,登录完了之后应该跳回我刚刚的业务,就是结算业务,但是还是跳到了主页,这样很难受啊,我还要再写一段业务

image

image

image

image

注意看最后一张图片上我写的批注

流程:

image

image

image

image

image

image

image

image

image

image

这就是整个业务流程,走完了。去拿快递,

希望今年会有好运把,也希望所有付出都有回报吧,谢谢,2018再见不再会。

2.5 提交订单

2.5.1 提交订单数据库分析

image

image

image

image

image

image

2.5.2 提交订单页面分析

image

image

image

image

image

image

image

image

image

上面图片中做了批注,各个pojo对应的信息


现在我们需要将三个pojo组合起来成一个pojo然后去接受表单传入的参数,怎么组合呢??

可以这样,我们继承TbOrder对象,然后在其中加入一个List和一个TbOrderShipping这样就省不少功夫

2.5.3 创建接收表单信息的pojo

image

将来我们这个pojo需要在web工程中来接受参数信息,然后传入Service工程中,所以首先这个pojo要在网路上传输,是不是要实现序列化接口,然后就是我们要将这个pojo放在哪?

如果放在Order-web工程中,那么Order-Service工程中又要依赖Order-web工程,显然我们这两个工程不能互相依赖嘛,如果web和service(服务层)相互依赖了,我们这个分布式就没啥意义了,所以这个pojo放在这两个中任何一个都不行

还有一个Order-Interface,我们的Order-Service依赖Interface,我们的Order-web工程也依赖Order-Interface,因为这两个工程通过接口来使用dubbo啊,所以我们将这个pojo写入Order-interface工程中。
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
/**
* @author RickYinPeng
* @ClassName OrderInfo
* @Description 接受订单信息
* @date 2019/1/2/15:23
*/
public class OrderInfo extends TbOrder{

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;
}
}

2.5.4 Dao层

可以使用逆向工程

2.5.5 Service层

接口

image

1
2
3
4
5
6
7
8
9
10
public interface OrderService {

/**
* 提交订单服务
* @param orderInfo 接受表单信息的pojo
* @return
*/
E3Result createOrder(OrderInfo orderInfo);

}
实现类

image

image

image

image

image

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
71
72
73
74
75
76
77
/**
* @author RickYinPeng
* @ClassName OrderServiceImpl
* @Description 订单处理服务
* @date 2019/1/2/15:45
*/
public class OrderServiceImpl implements OrderService{

@Autowired
private TbOrderMapper tbOrderMapper;

@Autowired
private TbOrderItemMapper tbOrderItemMapper;

@Autowired
private TbOrderShippingMapper tbOrderShippingMapper;

@Autowired
private JedisClient jedisClient;

@Value("${ORDER_ID_GEN_KEY}")
private String ORDER_ID_GEN_KEY;

@Value("${ORDER_ID_START}")
private String ORDER_ID_START;

@Value("${OREDER_DETAIL_ID_GEN_KEY}")
private String OREDER_DETAIL_ID_GEN_KEY;

@Override
public E3Result createOrder(OrderInfo orderInfo) {
//生成订单号,使用redis的incr生成
//给订单号设置初始值
if(!jedisClient.exists(ORDER_ID_GEN_KEY)){
jedisClient.set(ORDER_ID_GEN_KEY,ORDER_ID_START);
}
String order_id = jedisClient.incr(ORDER_ID_GEN_KEY).toString();

//补全TbOrder的属性
orderInfo.setOrderId(order_id);

//状态:1、未付款,2、已付款,3、未发货,4、已发货,5、交易成功,6、交易关闭
orderInfo.setStatus(1);

orderInfo.setCreateTime(new Date());
orderInfo.setUpdateTime(new Date());

//插入订单表
tbOrderMapper.insert(orderInfo);

//补全订单明细表信息
List<TbOrderItem> orderItems = orderInfo.getOrderItems();
for (TbOrderItem orderItem : orderItems) {
//生成明细id
String odid = jedisClient.incr(OREDER_DETAIL_ID_GEN_KEY).toString();
//补全pojo的属性
orderItem.setId(odid);
orderItem.setOrderId(order_id);

//向明细表插入数据
tbOrderItemMapper.insert(orderItem);
}

//补全物流表信息
TbOrderShipping orderShipping = orderInfo.getOrderShipping();
orderShipping.setOrderId(order_id);
orderShipping.setCreated(new Date());
orderShipping.setUpdated(new Date());

//向订单物流表插入数据
tbOrderShippingMapper.insert(orderShipping);

//返回E3Result,其中包含订单号

return E3Result.ok(order_id);
}
}
发布服务

image

2.5.6 表现层

引用服务

image

image

image

image

Controller
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
@RequestMapping(value = "/order/create",method = RequestMethod.POST)
public String createOrder(OrderInfo orderInfo,HttpServletRequest request){
//取用户信息
TbUser user = (TbUser) request.getAttribute("user");

//把用户信息添加到orderInfo中
orderInfo.setUserId(user.getId());
orderInfo.setBuyerNick(user.getUsername());

//调用服务生成订单
E3Result e3Result = orderService.createOrder(orderInfo);

//如果订单生成成功,需要删除购物车
if(e3Result.getStatus()==200){
//清空购物车
cartService.clearCartItem(user.getId());
}

//把订单号传递给页面
request.setAttribute("orderId",e3Result.getData());
request.setAttribute("payment",orderInfo.getPayment());

//返回逻辑视图
return "success";
}

image

image

image

image

系统测试

image

image

image

image