目录:
(1)业务介绍
(2)结算页
(3) 在 service-user模块获取地址列表
(4)在service-user-client暴露远程接口
(5)在service-cart模块获取选中商品数据
(6)创建service-cart-client模块
(7)搭建service-order模块
(1)业务介绍
订单业务在整个电商平台中处于核心位置,也是比较复杂的一块业务。是把“物”变为“钱”的一个中转站。
整个订单模块一共分四部分组成:
- 结算
- 下单
- 对接支付服务
- 对接库存管理系统
(2)结算页
入口:购物车点击计算按钮 ,结算必须要登录!
分析页面需要的数据:
- 需要用户地址信息
- 购物车中选择的商品列表
- 用户地址信息在service-user模块,购物车信息在service-cart模块,所以我们要在相应模块提供api接口,通过feign client调用获取数据
点击结算到结算页的流程:
(3) 在 service-user模块获取地址列表
添加mapper
package com.atguigu.gmall.user.mapper;
@Mapper
public interface UserAddressMapper extends BaseMapper<UserAddress> {
}
编写接口
package com.atguigu.gmall.user.service;
public interface UserAddressService {
/**
* 根据用户Id 查询用户的收货地址列表!
* @param userId
* @return
*/
List<UserAddress> findUserAddressListByUserId(String userId);
}
实现类
package com.atguigu.gmall.user.service.impl;
@Service
public class UserAddressServiceImpl implements UserAddressService {
@Autowired
private UserAddressMapper userAddressMapper;
@Override
public List<UserAddress> findUserAddressListByUserId(String userId) {
// 操作哪个数据库表,则就使用哪个表对应的mapper!
// new Example() ; 你操作的哪个表,则对应的传入表的实体类!
// select * from userAddress where userId = ?;
QueryWrapper<UserAddress> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId);
List<UserAddress> userAddressList = userAddressMapper.selectList(queryWrapper);
return userAddressList;
}
}
用户地址实体类:UserAddress
package com.atguigu.gmall.model.user;
import com.atguigu.gmall.model.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(description = "用户地址")
@TableName("user_address")
public class UserAddress extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "用户地址")
@TableField("user_address")
private String userAddress;
@ApiModelProperty(value = "用户id")
@TableField("user_id")
private Long userId;
@ApiModelProperty(value = "收件人")
@TableField("consignee")
private String consignee;
@ApiModelProperty(value = "联系方式")
@TableField("phone_num")
private String phoneNum;
@ApiModelProperty(value = "是否是默认")
@TableField("is_default")
private String isDefault;
}
创建控制器
package com.atguigu.gmall.user.controller;
@RestController
@RequestMapping("/api/user")
public class UserApiController {
@Autowired
private UserAddressService userAddressService;
/**
* 获取用户地址
* @param userId
* @return
*/
@GetMapping("inner/findUserAddressListByUserId/{userId}")
public List<UserAddress> findUserAddressListByUserId(@PathVariable("userId") String userId){
return userAddressService.findUserAddressListByUserId(userId);
}
}
(4)在service-user-client暴露远程接口
接口类
package com.atguigu.gmall.user.client;
@FeignClient(value = "service-user", fallback = UserDegradeFeignClient.class)
public interface UserFeignClient {
@GetMapping("/api/user/inner/findUserAddressListByUserId/{userId}")
List<UserAddress> findUserAddressListByUserId(@PathVariable(value = "userId") String userId);
}
package com.atguigu.gmall.user.client.impl;
@Component
public class UserDegradeFeignClient implements UserFeignClient {
@Override
public List<UserAddress> findUserAddressListByUserId(String userId) {
return null;
}
}
(5)在service-cart模块获取选中商品数据
添加接口:CartService 接口
/**
* 根据用户Id 查询购物车列表
*
* @param userId
* @return
*/
List<CartInfo> getCartCheckedList(String userId);
实现类
@Override
public List<CartInfo> getCartCheckedList(String userId) {
// 获取的选中的购物车列表!
String cartKey = this.getCartKey(userId);
// 获取到购物车集合数据:
List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartKey);
List<CartInfo> cartInfos = cartInfoList.stream().filter(cartInfo -> {
// 再次确认一下最新价格
cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
//判断是否选中,返回选中的 true返回 filter过滤出来选中的
return cartInfo.getIsChecked().intValue() == 1;
}).collect(Collectors.toList());
// 返回数据
return cartInfos;
}
购物车实体类:CartInfo
package com.atguigu.gmall.model.cart;
import com.atguigu.gmall.model.activity.CouponInfo;
import com.atguigu.gmall.model.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.List;
@Data
@ApiModel(description = "购物车")
@TableName("cart_info")
public class CartInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "用户id")
private String userId;
@ApiModelProperty(value = "skuid")
private Long skuId;
@ApiModelProperty(value = "放入购物车时价格")
private BigDecimal cartPrice;
@ApiModelProperty(value = "数量")
private Integer skuNum;
@ApiModelProperty(value = "图片文件")
private String imgUrl;
@ApiModelProperty(value = "sku名称 (冗余)")
private String skuName;
@ApiModelProperty(value = "isChecked")
private Integer isChecked = 1;
// 实时价格 skuInfo.price
BigDecimal skuPrice;
// 优惠券信息列表
@ApiModelProperty(value = "购物项对应的优惠券信息")
@TableField(exist = false)
private List<CouponInfo> couponInfoList;
}
继续在ApiCartController中编写控制器
/**
* 根据用户Id 查询购物车列表
*
* @param userId
* @return
*/
@GetMapping("getCartCheckedList/{userId}")
public List<CartInfo> getCartCheckedList(@PathVariable(value = "userId") String userId) {
return cartService.getCartCheckedList(userId);
}
(6)创建service-cart-client模块
修改配置pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-client</artifactId>
<version>1.0</version>
</parent>
<artifactId>service-cart-client</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>service-cart-client</name>
<description>service-cart-client</description>
</project>
package com.atguigu.gmall.cart.client;
@FeignClient(value = "service-cart",fallback = CartDegradeFeignClient.class)
public interface CartFeignClient {
// 获取选中购物车列表!
@GetMapping("/api/cart/getCartCheckedList/{userId}")
public List<CartInfo> getCartCheckedList(@PathVariable String userId);
}
package com.atguigu.gmall.cart.client.impl;
@Component
public class CartDegradeFeignClient implements CartFeignClient {
@Override
public List<CartInfo> getCartCheckedList(String userId) {
return null;
}
}
(7)搭建service-order模块
搭建方式如service-cart
修改pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service</artifactId>
<version>1.0</version>
</parent>
<version>1.0</version>
<artifactId>service-order</artifactId>
<packaging>jar</packaging>
<name>service-order</name>
<description>service-order</description>
<dependencies>
<dependency>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-product-client</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-cart-client</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-user-client</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<finalName>service-order</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
添加配置
bootstrap.properties:
spring.application.name=service-order
spring.profiles.active=dev
spring.cloud.nacos.discovery.server-addr=192.168.200.129:8848
spring.cloud.nacos.config.server-addr=192.168.200.129:8848
spring.cloud.nacos.config.prefix=${spring.application.name}
spring.cloud.nacos.config.file-extension=yaml
spring.cloud.nacos.config.shared-configs[0].data-id=common.yaml
Nacos配置:
启动类
package com.atguigu.gmall.order;
@SpringBootApplication
@ComponentScan(basePackages = "com.atguigu.gmall")
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.atguigu.gmall")
public class ServiceOrderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceOrderApplication.class,args);
}
}
订单表:
id
主键。自动生成
consignee
收货人名称。页面获取
consignee_tel
收货人电话。页面获取
deliveryAddress
收货地址。页面获取
total_amount
总金额。计算
order_status
订单状态,用于显示给用户查看。设定初始值。
userId
用户Id。从拦截器已放到请求属性中。
payment_way
支付方式(网上支付、货到付款)。页面获取
orderComment
订单状态。页面获取
out_trade_no
第三方支付编号。按规则生成
create_time
创建时间。设当前时间
expire_time
失效时间,默认当前时间+1天
process_status
订单进度状态,程序控制、 后台管理查看。设定初始值,
tracking_no
物流编号,初始为空,发货后补充
parent_order_id
拆单时产生,默认为空
订单详情表:
id
主键,自动生成
order_id
订单编号,主表保存后给从表
sku_id
商品id 页面传递
sku_name
商品名称,后台添加
img_url
图片路径,后台添加
order_price
购买价格(下单时的sku价格) 商品单价,从页面中获取,并验价。
sku_num
商品个数,从页面中获取
添加实体
package com.atguigu.gmall.model.order;
@Data
@ApiModel(description = "订单信息")
@TableName("order_info")
public class OrderInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "收货人")
@TableField("consignee")
private String consignee;
@ApiModelProperty(value = "收件人电话")
@TableField("consignee_tel")
private String consigneeTel;
@ApiModelProperty(value = "总金额")
@TableField("total_amount")
private BigDecimal totalAmount;
@ApiModelProperty(value = "订单状态")
@TableField("order_status")
private String orderStatus;
@ApiModelProperty(value = "用户id")
@TableField("user_id")
private Long userId;
@ApiModelProperty(value = "付款方式")
@TableField("payment_way")
private String paymentWay;
@ApiModelProperty(value = "送货地址")
@TableField("delivery_address")
private String deliveryAddress;
@ApiModelProperty(value = "订单备注")
@TableField("order_comment")
private String orderComment;
@ApiModelProperty(value = "订单交易编号(第三方支付用)")
@TableField("out_trade_no")
private String outTradeNo;
@ApiModelProperty(value = "订单描述(第三方支付用)")
@TableField("trade_body")
private String tradeBody;
@ApiModelProperty(value = "创建时间")
@TableField("create_time")
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date createTime;
@ApiModelProperty(value = "失效时间")
@TableField("expire_time")
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date expireTime;
@ApiModelProperty(value = "进度状态")
@TableField("process_status")
private String processStatus;
@ApiModelProperty(value = "物流单编号")
@TableField("tracking_no")
private String trackingNo;
@ApiModelProperty(value = "父订单编号")
@TableField("parent_order_id")
private Long parentOrderId;
@ApiModelProperty(value = "图片路径")
@TableField("img_url")
private String imgUrl;
@TableField(exist = false)
private List<OrderDetail> orderDetailList;
@TableField(exist = false)
private String wareId;
// 计算总价格
public void sumTotalAmount(){
BigDecimal totalAmount=new BigDecimal("0");
for (OrderDetail orderDetail : orderDetailList) {
totalAmount= totalAmount.add(orderDetail.getOrderPrice().multiply(new BigDecimal(orderDetail.getSkuNum())));
}
this.totalAmount= totalAmount;
}
}
package com.atguigu.gmall.model.order;
@Data
@ApiModel(description = "订单明细")
@TableName("order_detail")
public class OrderDetail extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "订单编号")
@TableField("order_id")
private Long orderId;
@ApiModelProperty(value = "sku_id")
@TableField("sku_id")
private Long skuId;
@ApiModelProperty(value = "sku名称(冗余)")
@TableField("sku_name")
private String skuName;
@ApiModelProperty(value = "图片名称(冗余)")
@TableField("img_url")
private String imgUrl;
@ApiModelProperty(value = "购买价格(下单时sku价格)")
@TableField("order_price")
private BigDecimal orderPrice;
@ApiModelProperty(value = "购买个数")
@TableField("sku_num")
private Integer skuNum;
// 是否有足够的库存!
@TableField(exist = false)
private String hasStock;
}
其中hasStock是一个非持久化属性,用户传递【是否还有库存】的标志。
如果商品在库存中有足够数据,suceess = “1”,fail=“0”
接口封装:
获取用户id:
package com.atguigu.gmall.order.controller;
@RestController
@RequestMapping("api/order")
public class OrderApiController {
@Autowired
private UserFeignClient userFeignClient;
@Autowired
private CartFeignClient cartFeignClient;
/**
* 确认订单
* @param request
* @return
*/
@GetMapping("auth/trade")
public Result<Map<String, Object>> trade(HttpServletRequest request) {
// 获取到用户Id
String userId = AuthContextHolder.getUserId(request);
//获取用户地址
List<UserAddress> userAddressList = userFeignClient.findUserAddressListByUserId(userId);
// 渲染送货清单
// 先得到用户想要购买的商品!
List<CartInfo> cartInfoList = cartFeignClient.getCartCheckedList(userId);
// 声明一个集合来存储订单明细
ArrayList<OrderDetail> detailArrayList = new ArrayList<>();
for (CartInfo cartInfo : cartInfoList) {
OrderDetail orderDetail = new OrderDetail();
orderDetail.setSkuId(cartInfo.getSkuId());
orderDetail.setSkuName(cartInfo.getSkuName());
orderDetail.setImgUrl(cartInfo.getImgUrl());
orderDetail.setSkuNum(cartInfo.getSkuNum());
orderDetail.setOrderPrice(cartInfo.getSkuPrice());
// 添加到集合
detailArrayList.add(orderDetail);
}
// 计算总金额
OrderInfo orderInfo = new OrderInfo();
orderInfo.setOrderDetailList(detailArrayList);
//调用对象里面的封装好的方法获总金额
orderInfo.sumTotalAmount();
Map<String, Object> result = new HashMap<>();
result.put("userAddressList", userAddressList);
result.put("detailArrayList", detailArrayList);
// 保存总金额
result.put("totalNum", detailArrayList.size());
result.put("totalAmount", orderInfo.getTotalAmount());
return Result.ok(result);
}
}
说明:接口已经封装,接下来暴露接口,提供给web-all模块前端展示数据