微服务商城系统(十三)订单、支付流程分析
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了微服务商城系统(十三)订单、支付流程分析,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含10757字,纯文字阅读大概需要16分钟。
内容图文
文章目录
一、订单
1、登录页面配置
前面使用的都是采用 Postman 实现登录,现在实现 oauth 自定义登录。
先 将登录相关的静态资源导入到 changgou-user-oauth 中:
导入 thymeleaf 模板引擎依赖:
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
提供控制器 com.changgou.oauth.controller.LoginRedirect,实现登录页跳转:
@Controller
@RequestMapping(value = "/oauth")
public class LoginRedirect {
/***
* 跳转到登录页面
* @return
*/
@GetMapping(value = "/login")
public String login(){
return "login";
}
}
针对静态资源和登录页面,我们需要实现忽略安全配置,并且要指定登录页面。修改com.changgou.oauth.config.WebSecurityConfig 的 2 个 configure 方法:
第 2 个 configure 配置:
测试:
点击登录按钮,访问之前的登录方法实现登录,需要对登录页做一下调整。
首先,修改 login.html,引入 thymeleaf 命名空间:
点击登录按钮,使用 vue+axios 实现登录,需要定义脚本,访问后台登录方法。
先添加 vue 入口标签,修改 login.html,添加id=“app” :
引入 js:
登录脚本实现:
修改表单:
测试:输入用户名和密码都是 changgou,点击”登录“按钮,页面显示 ”正在登录“后跳转至:
用户未登录的时候,并清除 Cookie ,直接访问购物车:
可以看到,返回的只是个错误状态码,不方便测试,可以设置为重定向到登录页面,让用户登录。需要修改网关的头文件,让用户每次没登录的时候,都跳转到登录页面。
修改 changgou-gateway-web 的 com.changgou.filter.AuthorizeFilter,代码如下:
此时再测试,未登录时访问购物车页面,就可以跳转到登录页面了。当然,在实际应用中,这里不能直接跳转到登录页,应该提示状态给页面,让页面根据判断跳转,这里只是为了方便测试。
现在还有个问题,如果未登录访问购物车,会跳转到登录页面,但是登录成功后,却并没有再返回到要访问的购物车页面。可以将用户要访问的页面作为参数传递给登录控制器,登录控制器记录下来,每次登录成功后,再跳转记录访问路劲参数指定的页面。
先修改网关,携带当前 URI。修改 changgou-gateway-web 的 com.changgou.filter.AuthorizeFilter,在之前的 URL 后面添加 FROM 参数以及 FROM 参数的值为 request.getURI(),代码如下:
再修改 changgou-user-oauth 的 com.changgou.oauth.controller.LoginRedirect 记录访问来源页,使 认证服务器获取 FROM 参数:
@GetMapping(value = "/login")
public String login(@RequestParam(value = "FROM",required = false,defaultValue = "")
String from, Model model){
model.addAttribute("from",from);
return "login";
}
修改页面,获取来源页信息,并存到 from 变量中,登录成功后跳转到该地址。
这里的计时跳转逻辑是有问题的,到时间并没能跳转,改成:
此时再测试,就可以识别未登录用户,跳转到登录页,然后根据登录状态,如果登录成功,则跳转到来源页。
2、用户收件地址查询
订单的前端页面是这样的:
这里,“收件人信息”,是从 user 工程中获取到的,在数据库中对应 tb_address 表:
对应表结构:
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;
需要在 user 工程中提供根据用户名查询收件地址的方法。
在 AddressService 中提供方法:
List<Address> list(String username);
实现:
@Override
public List<Address> list(String username) {
Address address = new Address();
address.setUsername(username);
return addressMapper.select(address);
}
控制层:
@GetMapping("/user/list")
public Result<List<Address>> list(){
// 获取用户登录名
String username = tokenDecode.getUserInfo().get("username");
List<Address> address=addressService.list(username);
return new Result<>(true,StatusCode.OK,"查询成功",address);
}
运行结果:
送货清单其实就是购物车列表,直接查询之前的购物车列表即可。
3、 下单
点击结算页的时候,会立即创建订单数据,创建订单数据会将数据存入到 2 张表中,分别是 订单表 和 订单明细表,此处还需要修改商品对应的库存数量。
而且提交订单后,需要把商品详情从用户的购物车中删除;需要进行价格校验,检查价格是否变化,以当前数据库中的价格为准,以防出现 “异价” 的问题;需要检查库存,特别是并非库存,以防出现 “超卖” 的问题。
(1)表结构介绍
订单表:
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;
两个表通过外键 orde_id 进行连结。
(2)下单实现
下单的时候,先添加订单,向 tb_order 表中增加数据,再添加订单明细,向 tb_order_item 表中增加数据。
需要修改 changgou-service-order 微服务,实现下单操作,这里会生成订单号,我们首先需要在 启动类 中创建一个 IdWorker 对象( 为什么不使用自增 ID 呢?因为可能存在重复 和 数值超出范围 问题):
@Bean
public IdWorker idWorker(){
return new IdWorker(1,1);
}
- 业务层
修改 changgou-service-order 微服务,修改com.changgou.order.service.impl.OrderServiceImpl:
void addOrder(Order order);
实现:
@Override
public void addOrder(Order order) {
// 订单主键
order.setId(String.valueOf(idWorker.nextId()));
// 总数量
int totolNum = 0;
// 总金额
int totalMoney = 0;
// 获取订单(购物车)明细
List<OrderItem> orderItem = redisTemplate.boundHashOps("Cart_" + order.getUsername()).values();
for (OrderItem item : orderItem) {
// 价格校验
int price = orderItemMapper.selectByPrimaryKey(item.getId()).getPrice();
if (price == item.getMoney()) {
// 总金额
totalMoney += item.getMoney();
} else totalMoney += price;
// 总数量
totolNum += item.getNum();
}
// 订单商品总数目 = 每个商品数量之和
order.setTotalNum(totolNum);
// 订单总金额 = 每个商品金额之和
order.setTotalMoney(totalMoney);
// 订单实付金额 = 每个商品实付金额之和
order.setPayMoney(totalMoney);
// 订单优惠金额 = 总金额 - 实付金额,暂时为 0
order.setPreMoney(0);
// 订单创建时间
order.setCreateTime(new Date());
// 订单修改时间
order.setUpdateTime(order.getCreateTime());
// 订单评价状态,0 表示未评价,1 表示已评价
order.setBuyerRate("0");
// 订单来源,1 表示 Web
order.setSourceType("1");
// 订单状态,0 表示未完成,1 表示已完成,2 表示已退货
order.setOrderStatus("0");
// 订单支付状态,0 表示未支付,1 表示已支付,2 表示支付失败
order.setPayStatus("0");
// 订单删除状态,0 表示未删除
order.setIsDelete("0");
// 订单发货状态,0 表示未发货,1 表示已发货,2 表示已收货
order.setConsignStatus("0");
// 先添加订单信息
orderMapper.insertSelective(order);
// 再添加订单明细信息
for (OrderItem item : orderItem) {
item.setId(String.valueOf(idWorker.nextId()));
// 是否退货,0 表示未退货,1 表示已退货
item.setIsReturn("0");
item.setOrderId(order.getId());
// 退货状态,0 表示未退货
item.setIsReturn("0");
orderItemMapper.insertSelective(item);
}
// 下单后需要把商品从购物车中移除
redisTemplate.delete("Cart_" + order.getUsername());
}
可以看到,逻辑是传来 order 对象, 从 Redis 中查到 “Cart_xxx” 为命名空间的记录对应的 value,也就是 xxx 用户购物车/订单的所有记录,遍历,求出总金额和数量;再为 order 对象设置属性,将 order 对象持久化到 order 表中,再遍历一次 Redis 中的记录,把这些记录都持久化到 order_item 表中,下单后还需要把 xxx 用户购物车中的所有记录移除。
这里,通用 Mapper 使用的是 insertSelective 方法。 如果使用的是 insert ,那么所有的字段都会添加一遍,即使有的字段没有值;如果使用 inserSelective 就会只给有值的字段赋值(会对传进来的值做非空判断)。还有要注意的是,在启动类用 @MapperScan 注解,导入的包应该是 tk 的,而不是 spring mybatis 的。
( RedisTemplate 中的命名空间、key、value 的关系示意图:
可以看到,用用户名作命名空间,商品的 sku ID 作 key,商品详情的 orderItem 作 value,这设计挺巧妙的
内容总结
以上是互联网集市为您收集整理的微服务商城系统(十三)订单、支付流程分析全部内容,希望文章能够帮你解决微服务商城系统(十三)订单、支付流程分析所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。