订单结算页
用户从购物车页面点击结算,跳转到订单结算页,结算页需要加载用户对应的收件地址,如下图:
表结构分析:
CREATE TABLE `tb_address` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL COMMENT '用户名',
`provinceid` varchar(20) DEFAULT NULL COMMENT '省',
`cityid` varchar(20) DEFAULT NULL COMMENT '市',
`areaid` varchar(20) DEFAULT NULL COMMENT '县/区',
`phone` varchar(20) DEFAULT NULL COMMENT '电话',
`address` varchar(200) DEFAULT NULL COMMENT '详细地址',
`contact` varchar(50) DEFAULT NULL COMMENT '联系人',
`is_default` varchar(1) DEFAULT NULL COMMENT '是否是默认 1默认 0否',
`alias` varchar(50) DEFAULT NULL COMMENT '别名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8;
我们可以根据用户登录名去tb_address表中查询对应的数据。
代码实现用户收件地址查询
控制层
修改changgou-service-user微服务,修改com.changgou.user.controller.AddressController,添加
根据用户名查询用户收件信息方法
业务层接口
修改changgou-service-user微服务,需改com.changgou.user.service.AddressService接口,添加
根据用户名字查询用户收件地址信息
业务层接口实现类
修改changgou-service-user微服务,修改com.changgou.user.service.impl.AddressServiceImpl
类,添加根据用户查询用户收件地址信息实现方法
/****
* 用户收件地址
*/
@GetMapping(value = "/user/list")
public Result<List<Address>> list(){
//获取用户登录信息
Map<String, String> userMap = TokenDecode.getUserInfo();
String username = userMap.get("username");
//查询用户收件地址
List<Address> addressList = addressService.list(username);
return new Result(true, StatusCode.OK,"查询成功!",addressList);
}
/***
* 收件地址查询
* @param username
* @return
*/
List<Address> list(String username);
/***
* 收件地址查询
* @param username
* @return
*/
@Override
public List<Address> list(String username) {
Address address = new Address();
address.setUsername(username);
return addressMapper.select(address);
}
测试:http://localhost:8001/api/address/user/list
运送清单
运送清单其实就是购物车列表,直接查询之前的购物车列表即可,这里不做说明了。
下单
业务分析
点击结算页的时候,会立即创建订单数据,创建订单数据会将数据存入到2张表中,分别是订单表
和订单明细表,此处还需要修改商品对应的库存数量。
订单表结构如下:
CREATE TABLE `tb_order` (
`id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT '订单id',
`total_num` int(11) DEFAULT NULL COMMENT '数量合计',
`total_money` int(11) DEFAULT NULL COMMENT '金额合计',
`pre_money` int(11) DEFAULT NULL COMMENT '优惠金额',
`post_fee` int(11) DEFAULT NULL COMMENT '邮费',
`pay_money` int(11) DEFAULT NULL COMMENT '实付金额',
`pay_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付类型,1、在线支付、0 货到付款',
`create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
`update_time` datetime DEFAULT NULL COMMENT '订单更新时间',
`pay_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 '物流单号',
`username` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '用户名称',
`buyer_message` varchar(1000) COLLATE utf8_bin DEFAULT NULL COMMENT '买家留言',
`buyer_rate` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否评价',
`receiver_contact` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人',
`receiver_mobile` varchar(12) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人手机',
`receiver_address` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人地址',
`source_type` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '订单来源:1:web,2:app,3:微信公众号,4:微信小程序 5 H5手机页面',
`transaction_id` varchar(30) COLLATE utf8_bin DEFAULT NULL COMMENT '交易流水号',
`order_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '订单状态,0:未完成,1:已完成,2:已退货',
`pay_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付状态,0:未支付,1:已支付,2:支付失败',
`consign_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '发货状态,0:未发货,1:已发货,2:已收货',
`is_delete` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否删除',
PRIMARY KEY (`id`),
KEY `create_time` (`create_time`),
KEY `status` (`order_status`),
KEY `payment_type` (`pay_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
订单明细表结构如下:
CREATE TABLE `tb_order_item` (
`id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT 'ID',
`category_id1` int(11) DEFAULT NULL COMMENT '1级分类',
`category_id2` int(11) DEFAULT NULL COMMENT '2级分类',
`category_id3` int(11) DEFAULT NULL COMMENT '3级分类',
`spu_id` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT 'SPU_ID',
`sku_id` bigint(20) NOT NULL COMMENT 'SKU_ID',
`order_id` bigint(20) NOT NULL COMMENT '订单ID',
`name` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品名称',
`price` int(20) DEFAULT NULL COMMENT '单价',
`num` int(10) DEFAULT NULL COMMENT '数量',
`money` int(20) DEFAULT NULL COMMENT '总金额',
`pay_money` int(11) DEFAULT NULL COMMENT '实付金额',
`image` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '图片地址',
`weight` int(11) DEFAULT NULL COMMENT '重量',
`post_fee` int(11) DEFAULT NULL COMMENT '运费',
`is_return` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否退货,0:未退货,1:已退货',
PRIMARY KEY (`id`),
KEY `item_id` (`sku_id`),
KEY `order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
下单实现
下单的时候,先添加订单往tb_order表中增加数据,再添加订单明细往tb_order_item表中增加数据。
代码实现
先修改changgou-service-order微服务,实现下单操作,这里会生成订单号,我们首先需要在启动类中创建一个IdWorker对象。
在com.changgou.OrderApplication
中创建IdWorker,代码如下:
@Bean
public IdWorker idWorker(){
return new IdWorker(1,1);
}
(1)业务层
修改changgou-service-order微服务,修改com.changgou.order.service.impl.OrderServiceImpl
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderItemMapper orderItemMapper;
@Autowired
private CartService cartService;
@Autowired
private IdWorker idWorker;
@Autowired
private RedisTemplate redisTemplate;
/***
* 添加订单
* @param order
* @return
*/
@Override
public int add(Order order) {
//查询出用户的所有购物车
List<OrderItem> orderItems = cartService.list(order.getUsername());
//统计计算
int totalMoney = 0;
int totalPayMoney=0;
int num = 0;
for (OrderItem orderItem : orderItems) {
//总金额
totalMoney+=orderItem.getMoney();
//实际支付金额
totalPayMoney+=orderItem.getPayMoney();
//总数量
num+=orderItem.getNum();
}
order.setTotalNum(num);
order.setTotalMoney(totalMoney);
order.setPayMoney(totalPayMoney);
order.setPreMoney(totalMoney-totalPayMoney);
//其他数据完善
order.setCreateTime(new Date());
order.setUpdateTime(order.getCreateTime());
order.setBuyerRate("0"); //0:未评价,1:已评价
order.setSourceType("1"); //来源,1:WEB
order.setOrderStatus("0"); //0:未完成,1:已完成,2:已退货
order.setPayStatus("0"); //0:未支付,1:已支付,2:支付失败
order.setConsignStatus("0"); //0:未发货,1:已发货,2:已收货
order.setId("NO."+idWorker.nextId());
int count = orderMapper.insertSelective(order);
//添加订单明细
for (OrderItem orderItem : orderItems) {
orderItem.setId("NO."+idWorker.nextId());
orderItem.setIsReturn("0");
orderItem.setOrderId(order.getId());
orderItemMapper.insertSelective(orderItem);
}
//清除Redis缓存购物车数据
redisTemplate.delete("Cart_"+order.getUsername());
return count;
}
}
(2)控制层
修改changgou-service-order微服务,修改com.changgou.order.controller.OrderController类
@Autowired
private TokenDecode tokenDecode;
/***
* 新增Order数据
* @param order
* @return
*/
@PostMapping
public Result add(@RequestBody Order order){
//获取用户名
Map<String, String> userMap = tokenDecode.getUserInfo();
String username = userMap.get("username");
//设置购买用户
order.setUsername(username);
orderService.add(order);
return new Result(true,StatusCode.OK,"添加成功");
}
测试
保存订单测试,表数据变化如下:
库存变更
业务分析
上面操作只实现了下单操作,但对应的库存还没跟着一起减少,我们在下单之后,应该调用商品微
服务,将下单的商品库存减少,销量增加。每次订单微服务只需要将用户名传到商品微服务,商品
微服务通过用户名到Redis中查询对应的购物车数据,然后执行库存减少,库存减少需要控制当前
商品库存>=销售数量。
如何控制库存数量>=销售数量呢?其实可以通过SQL语句实现,每次减少数量的时候,加个条件判断,where num>=#{num}
即可。
该工程中一会儿需要查询购物车数据,所以需要引入订单的api,在pom.xml中添加如下依赖:
<!--order api 依赖-->
<dependency>
<groupId>com.changgou</groupId>
<artifactId>changgou-service-order-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
代码实现
要调用其他微服务,需要将头文件中的令牌数据携带到其他微服务中取,所以我们不能使用hystrix
的多线程模式,修改changgou-service-goods的applicatin.yml配置,代码如下:
#hystrix 配置
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 10000
strategy: SEMAPHORE
每次还需要使用拦截器添加头文件信息,修改配置类com.changgou.GoodsApplication添加拦截器,代码如下:
@Bean
public FeignInterceptor feignInterceptor(){
return new FeignInterceptor();
}
(1)Dao层
修改changgou-service-goods微服务的com.changgou.goods.dao.SkuMapper
接口,增加库存递减方法,代码如下:
/**
* 递减库存
* @param orderItem
* @return
*/
@Update("UPDATE tb_sku SET num=num-#{num},sale_num=sale_num+#{num} WHERE id=#{skuId} AND num>=#{num}")
int decrCount(OrderItem orderItem);
(2)业务层
修改changgou-service-goods微服务的com.changgou.goods.service.SkuService
接口,添加如下方法:
/***
* 库存递减
* @param username
*/
void decrCount(String username);
修改changgou-service-goods微服务的com.changgou.goods.service.impl.SkuServiceImpl
实现类,添加一个实现方法,代码如下:
@Autowired
private RedisTemplate redisTemplate;
/***
* 库存递减
* @param username
*/
@Override
public void decrCount(String username) {
//获取购物车数据
List<OrderItem> orderItems = redisTemplate.boundHashOps("Cart_" + username).values();
//循环递减
for (OrderItem orderItem : orderItems) {
//递减库存
int count = skuMapper.decrCount(orderItem);
if(count<=0){
throw new RuntimeException("库存不足,递减失败!");
}
}
}
(3)控制层
修改changgou-service-goods的com.changgou.goods.controller.SkuController
类,添加库存递减方法,代码如下:
/***
* 库存递减
* @param username
* @return
*/
@PostMapping(value = "/decr/count")
public Result decrCount(String username){
//库存递减
skuService.decrCount(username);
return new Result(true,StatusCode.OK,"库存递减成功!");
}
(4)创建feign
同时在changgou-service-goods-api工程添加com.changgou.goods.feign.SkuFeign
的实现,代码如下:
/***
* 库存递减
* @param username
* @return
*/
@PostMapping(value = "/decr/count")
Result decrCount(@RequestParam(value = "username") String username);
调用库存递减
修改changgou-service-order微服务的com.changgou.order.service.impl.OrderServiceImpl类的add方法,增加库存递减的调用。
先注入SkuFeign
@Autowired
private SkuFeign skuFeign;
再调用库存递减方法
//库存减库存
skuFeign.decrCount(order.getUsername());
完整代码如下:
测试
库存减少前,查询数据库Sku数据如下:个数98,销量0
使用Postman执行 http://localhost:18081/api/order/add
增加积分
比如每次下单完成之后,给用户增加10个积分,支付完成后赠送优惠券,优惠券可用于支付时再次抵扣。
我们先完成增加积分功能。如下表:points表示用户积分
CREATE TABLE `tb_user` (
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) NOT NULL COMMENT '密码,加密存储',
`phone` varchar(20) DEFAULT NULL COMMENT '注册手机号',
`email` varchar(50) DEFAULT NULL COMMENT '注册邮箱',
`created` datetime NOT NULL COMMENT '创建时间',
`updated` datetime NOT NULL COMMENT '修改时间',
`source_type` varchar(1) DEFAULT NULL COMMENT '会员来源:1:PC,2:H5,3:Android,4:IOS',
`nick_name` varchar(50) DEFAULT NULL COMMENT '昵称',
`name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`status` varchar(1) DEFAULT NULL COMMENT '使用状态(1正常 0非正常)',
`head_pic` varchar(150) DEFAULT NULL COMMENT '头像地址',
`qq` varchar(20) DEFAULT NULL COMMENT 'QQ号码',
`is_mobile_check` varchar(1) DEFAULT '0' COMMENT '手机是否验证 (0否 1是)',
`is_email_check` varchar(1) DEFAULT '0' COMMENT '邮箱是否检测(0否 1是)',
`sex` varchar(1) DEFAULT '1' COMMENT '性别,1男,0女',
`user_level` int(11) DEFAULT NULL COMMENT '会员等级',
`points` int(11) DEFAULT NULL COMMENT '积分',
`experience_value` int(11) DEFAULT NULL COMMENT '经验值',
`birthday` datetime DEFAULT NULL COMMENT '出生年月日',
`last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间',
PRIMARY KEY (`username`),
UNIQUE KEY `username` (`username`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';
代码实现
(1)dao层
修改changgou-service-user微服务的com.changgou.user.dao.UserMapper
接口,增加用户积分方法
/***
* 增加用户积分
* @param username
* @param pint
* @return
*/
@Update("UPDATE tb_user SET points=points+#{point} WHERE username=#{username}")
int addUserPoints(@Param("username") String username, @Param("point") Integer pint);
(2)业务层
修改changgou-service-user微服务的com.changgou.user.service.UserService
接口,代码如下:
/***
* 添加用户积分
* @param username
* @param pint
* @return
*/
int addUserPoints(String username,Integer pint);
修改changgou-service-user微服务的com.changgou.user.service.impl.UserServiceImpl
,增加添加积分方法实现,代码如下:
/***
* 修改用户积分
* @param username
* @param pint
* @return
*/
@Override
public int addUserPoints(String username, Integer pint) {
return userMapper.addUserPoints(username,pint);
}
(3)控制层
修改changgou-service-user微服务的com.changgou.user.controller.UserController
,添加增加用户积分方法,代码如下:
@Autowired
private TokenDecode tokenDecode;
/***
* 增加用户积分
* @param points:要添加的积分
*/
@GetMapping(value = "/points/add")
public Result addPoints(Integer points){
//获取用户名
Map<String, String> userMap = tokenDecode.getUserInfo();
String username = userMap.get("username");
//添加积分
userService.addUserPoints(username,points);
return new Result(true,StatusCode.OK,"添加积分成功!");
}
(4)Feign添加
修改changgou-service-user-api工程,修改com.changgou.user.feign.UserFeign
,添加增加用户积分方法,代码如下:
/***
* 添加用户积分
* @param points
* @return
*/
@GetMapping(value = "/points/add")
Result addPoints(@RequestParam(value = "points")Integer points);
增加积分调用
修改changgou-service-order,添加changgou-service-user-api的依赖,修改pom.xml,添加如下依赖:
<!--user api 依赖-->
<dependency>
<groupId>com.changgou</groupId>
<artifactId>changgou-service-user-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
在增加订单的时候,同时添加用户积分,修改changgou-service-order微服务的
com.changgou.order.service.impl.OrderServiceImpl
下单方法,增加调用添加积分方法
修改changgou-service-order的启动类com.changgou.OrderApplication
,添加feign的包路径: