day17_订单(结算,提交订单,支付页,立即购买,我的订单)

2024-03-09 11:28

本文主要是介绍day17_订单(结算,提交订单,支付页,立即购买,我的订单),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 订单模块
  • 1 结算
    • 1.1 需求说明
    • 1.2 获取用户地址
      • 1.2.1 UserAddress
      • 1.2.2 UserAddressController
      • 1.2.3 UserAddressService
      • 1.2.4 UserAddressMapper
      • 1.2.5 UserAddressMapper.xml
    • 1.3 获取购物项数据
      • 1.3.1 CartController
      • 1.3.2 CartService
      • 1.3.3 openFeign接口定义
    • 1.4 环境搭建(service-order)
    • 1.5 后端结算业务接口开发
      • 1.5.1 TradeVo
      • 1.5.2 OrderItem
      • 1.5.3 OrderInfoController
      • 1.5.4 OrderInfoService
      • 1.5.5 服务网关
    • 1.6 openFeign拦截器使用
      • 1.6.1 问题说明
      • 1.6.2 问题解决
  • 2 提交订单
    • 2.1 需求说明
    • 2.2 后端接口
      • 2.2.1 查询用户地址
        • 业务接口开发
          • UserAddressController
          • UserAddressService
          • UserAddressMapper
          • UserAddressMapper.xml
        • openFeign接口开发
      • 2.2.2 业务接口开发
        • OrderInfoDto
        • OrderLog
        • OrderInfoController
        • OrderInfoService
        • Mapper接口
          • OrderInfoMapper
          • OrderItemMapper
          • OrderLogMapper
        • XML映射文件
          • OrderInfoMapper.xml
          • OrderItemMapper.xml
          • OrderLogMapper.xml
      • 2.2.3 清空购物车
        • service-cart
          • CartController
          • CartService
        • openFeign接口
        • service-order
  • 3 支付页
    • 3.1 需求说明
    • 3.2 后端接口
      • 3.2.1 OrderInfoController
      • 3.2.2 OrderInfoService
      • 3.2.3 OrderInfoMapper
      • 3.2.4 OrderInfoMapper.xml
  • 4 立即购买
    • 4.1 需求说明
    • 4.2 后端接口
      • 4.2.1 OrderInfoController
      • 4.2.2 OrderInfoService
  • 5 我的订单
    • 5.1 需求说明
    • 5.2 后端接口
      • 5.2.1 OrderInfoController
      • 5.2.2 OrderInfoService
      • 5.2.3 OrderInfoMapper
      • 5.2.4 OrderInfoMapper.xml
      • 5.2.5 OrderInfo
      • 5.2.6 OrderItemMapper.xml
      • 5.2.7 OrderItemMapper
      • 5.2.4 OrderInfoMapper.xml
      • 5.2.5 OrderInfo
      • 5.2.6 OrderItemMapper.xml
      • 5.2.7 OrderItemMapper

订单模块

1 结算

1.1 需求说明

入口:购物车点击去结算按钮 ,进入结算页面(订单确认页面),如图所示:

在这里插入图片描述

分析页面需要的数据:

1、 用户地址信息列表,结算页选中默认地址

2、 购物车中选择的商品列表,及商品的总金额

查看接口文档:

获取用户地址信息列表接口地址及返回结果:

get /api/user/userAddress/auth/findUserAddressList
返回结果:
{"code": 200,"message": "操作成功","data": [{"id": 1,"createTime": "2023-05-12 17:50:41","updateTime": "2023-06-02 19:15:17","isDeleted": 0,"userId": 1,"name": "晴天","phone": "15014526352","tagName": "家","provinceCode": "110000","cityCode": "110100","districtCode": "110114","address": "天通苑大街1号","fullAddress": "北京市北京市昌平区天通苑大街1号","isDefault": 0},...]
}

结算接口地址及返回结果:

get api/order/orderInfo/auth/trade
返回结果:
{"code": 200,"message": "操作成功","data": {"totalAmount": 6997.00,"orderItemList": [{"skuId": 1,"skuName": "小米 红米Note10 5G手机 颜色:白色 内存:8G","thumbImg": "http://139.198.127.41:9000/spzx/20230525/665832167-5_u_1 (1).jpg","skuPrice": 1999.00,"skuNum": 2},...]}
} 

获取用户地址列表调用流程如下所示:

在这里插入图片描述

获取购物车中选中的商品列表调用流程如下所示:

在这里插入图片描述

1.2 获取用户地址

在service-user模块中开发一个获取地址列表接口,供service-order微服务进行调用。

1.2.1 UserAddress

针对当前要操作的数据定义一个与之对应的实体类:

//com.atguigu.spzx.model.entity.user;
@Data
@Schema(description = "用户地址实体类")
public class UserAddress extends BaseEntity {private static final long serialVersionUID = 1L;@Schema(description = "用户ID")private Long userId;@Schema(description = "name")private String name;@Schema(description = "电话")private String phone;@Schema(description = "标签名称")private String tagName;@Schema(description = "provinceCode")private String provinceCode;@Schema(description = "cityCode")private String cityCode;@Schema(description = "districtCode")private String districtCode;@Schema(description = "详细地址")private String address;@Schema(description = "完整地址")private String fullAddress;@Schema(description = "是否默认地址(0:否 1:是)")private Integer isDefault;}

1.2.2 UserAddressController

表现层代码:

// com.atguigu.spzx.user.controller;
@Tag(name = "用户地址接口")
@RestController
@RequestMapping(value="/api/user/userAddress")
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserAddressController {@Autowiredprivate UserAddressService userAddressService;@Operation(summary = "获取用户地址列表")@GetMapping("auth/findUserAddressList")public Result<List<UserAddress>> findUserAddressList() {List<UserAddress> list = userAddressService.findUserAddressList();return Result.build(list , ResultCodeEnum.SUCCESS) ;}
}

1.2.3 UserAddressService

业务层代码实现:

//业务接口
public interface UserAddressService {List<UserAddress> findUserAddressList();
}//业务接口实现
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserAddressServiceImpl implements UserAddressService {@Autowiredprivate UserAddressMapper userAddressMapper;@Overridepublic List<UserAddress> findUserAddressList() {Long userId = AuthContextUtil.getUserInfo().getId();return userAddressMapper.findByUserId(userId);}
}

1.2.4 UserAddressMapper

持久层代码实现:

@Mapper
public interface UserAddressMapper {List<UserAddress> findByUserId(Long userId);
}

1.2.5 UserAddressMapper.xml

在映射文件中定义对应的sql语句:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.atguigu.spzx.user.mapper.UserAddressMapper"><resultMap id="userAddressMap" type="com.atguigu.spzx.model.entity.user.UserAddress" autoMapping="true"></resultMap><!-- 用于select查询公用抽取的列 --><sql id="columns">id,user_id,name,phone,tag_name,province_code,city_code,district_code,address,full_address,is_default,create_time,update_time,is_deleted</sql><select id="findByUserId" resultMap="userAddressMap">select <include refid="columns" />from user_addresswhereuser_id = #{userId}</select>
</mapper>

启动服务进行测试。

1.3 获取购物项数据

在service-cart微服务中开发一个接口,获取当前登录用户选中的购物项列表数据,如下所示:

1.3.1 CartController

表现层接口:

@Operation(summary="选中的购物车")
@GetMapping(value = "/auth/getAllCkecked")
public Result<List<CartInfo>> getAllCkecked() {List<CartInfo> cartInfoList = cartService.getAllCkecked() ;return Result.build(cartInfoList , ResultCodeEnum.SUCCESS) ;
}

1.3.2 CartService

业务层接口:

// 业务接口
List<CartInfo> getAllCkecked();// 业务接口实现类
@Override
public List<CartInfo> getAllCkecked() {Long userId = AuthContextUtil.getUserInfo().getId();String cartKey = getCartKey(userId);List<Object> objectList = redisTemplate.opsForHash().values(cartKey);       // 获取所有的购物项数据if(!CollectionUtils.isEmpty(objectList)) {List<CartInfo> cartInfoList = objectList.stream().map(cartInfoJSON -> JSON.parseObject(cartInfoJSON.toString(), CartInfo.class)).filter(cartInfo -> cartInfo.getIsChecked() == 1).collect(Collectors.toList());return cartInfoList ;}return new ArrayList<>() ;
}

1.3.3 openFeign接口定义

步骤:

1、在spzx-service-client模块下创建一个service-cart-client的子模块

2、在service-cart-client模块下定义远程openFeign接口

// com.atguigu.spzx.feign.cart;
@FeignClient(value = "service-cart" , fallback = CartFeignClientFallback.class)
public interface CartFeignClient {@GetMapping(value = "/api/order/cart/auth/getAllCkecked")public abstract Result<List<CartInfo>> getAllCkecked() ;}// com.atguigu.spzx.feign.cart.fallback;
@Slf4j
public class CartFeignClientFallback implements CartFeignClient {@Overridepublic Result<List<CartInfo>> getAllCkecked() {log.info("CartFeignClientFallback...getAllCkecked的方法执行了");return Result.build(null , ResultCodeEnum.SUCCESS) ;}
}

3、降级类自动化配置

在resources目录下创建一个MATE-INF/spring文件夹,在该文件夹下创建一个

org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,文件的中的内容如下所示:

com.atguigu.spzx.feign.cart.fallback.CartFeignClientFallback

1.4 环境搭建(service-order)

步骤:

1、在spzx-service模块下创建一个service-order微服务,并加入如下依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、准备application.yml、application-dev.yml、logback-spring.xml、mybatis-config.xml文件。文件内容如下所示:

server:port: 8514spring:application:name: service-ordercloud:nacos:discovery:server-addr: 192.168.136.142:8848sentinel:transport:dashboard: localhost:8080datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.136.142:3306/db_spzx?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=trueusername: rootpassword: 1234data:redis:host: 192.168.136.142port: 6379password: 1234mybatis:config-location: classpath:mybatis-config.xmlmapper-locations: classpath:mapper/*/*.xml
feign:sentinel:enabled: true

logback-spring.xml修改输出路径:

<property name="log.path" value="D://work//service-order//logs" />

mybatis-config.xml:从之前的模块中进行复制

3、创建启动类

//  com.atguigu.spzx.order;
@SpringBootApplication
@EnableFeignClients(basePackages = {"com.atguigu.spzx.feign.cart"
})
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class , args) ;}}

1.5 后端结算业务接口开发

操作模块:service-order

1.5.1 TradeVo

定义一个实体类用来封装结算的参数(根据接口文档进行定义),具体定义如下所示

// com.atguigu.spzx.model.vo.h5
@Data
@Schema(description = "结算实体类")
public class TradeVo {@Schema(description = "结算总金额")private BigDecimal totalAmount;@Schema(description = "结算商品列表")private List<OrderItem> orderItemList;}

1.5.2 OrderItem

定义一个与数据库表相对应的实体类,封装订单明细数据:

 // com.atguigu.spzx.model.entity.order
@Data
@Schema(description = "订单项实体类")
public class OrderItem extends BaseEntity {private static final long serialVersionUID = 1L;@Schema(description = "订单id")private Long orderId;@Schema(description = "商品sku编号")private Long skuId;@Schema(description = "商品sku名字")private String skuName;@Schema(description = "商品sku图片")private String thumbImg;@Schema(description = "商品sku价格")private BigDecimal skuPrice;@Schema(description = "商品购买的数量")private Integer skuNum;}

1.5.3 OrderInfoController

业务层代码实现:

@Tag(name = "订单管理")
@RestController
@RequestMapping(value="/api/order/orderInfo")
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoController {@Autowiredprivate OrderInfoService orderInfoService;@Operation(summary = "确认下单")@GetMapping("auth/trade")public Result<TradeVo> trade() {TradeVo tradeVo = orderInfoService.getTrade();return Result.build(tradeVo, ResultCodeEnum.SUCCESS);}}

1.5.4 OrderInfoService

业务层代码实现:

//业务接口
public interface OrderInfoService {TradeVo getTrade();
}//业务接口实现
// com.atguigu.spzx.order.service.impl;
@Service
public class OrderInfoServiceImpl implements OrderInfoService {@Autowiredprivate CartFeignClient cartFeignClient ;@Overridepublic TradeVo getTrade() {// 获取当前登录的用户的idLong userId = AuthContextUtil.getUserInfo().getId();// 获取选中的购物项列表数据List<CartInfo> cartInfoList = cartFeignClient.getAllCkecked().getData() ;List<OrderItem> orderItemList = new ArrayList<>();for (CartInfo cartInfo : cartInfoList) {        // 将购物项数据转换成功订单明细数据OrderItem orderItem = new OrderItem();orderItem.setSkuId(cartInfo.getSkuId());orderItem.setSkuName(cartInfo.getSkuName());orderItem.setSkuNum(cartInfo.getSkuNum());orderItem.setSkuPrice(cartInfo.getCartPrice());orderItem.setThumbImg(cartInfo.getImgUrl());orderItemList.add(orderItem);}// 计算总金额BigDecimal totalAmount = new BigDecimal(0);for(OrderItem orderItem : orderItemList) {totalAmount = totalAmount.add(orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuNum())));}TradeVo tradeVo = new TradeVo();tradeVo.setTotalAmount(totalAmount);tradeVo.setOrderItemList(orderItemList);return tradeVo;}}

1.5.5 服务网关

服务网关中配置service-order微服务的路由规则:

spring:cloud:gateway:routes:- id: service-orderuri: lb://service-orderpredicates:- Path=/api/order/orderInfo/**

启动服务进行测试。

1.6 openFeign拦截器使用

1.6.1 问题说明

在测试的时候,那么service-cart微服务会报错,如下所示:

java.lang.NullPointerException: Cannot invoke "com.atguigu.spzx.model.entity.user.UserInfo.getId()" because the return value of "com.atguigu.spzx.common.util.AuthContextUtil.getUserInfo()" is nullat com.atguigu.spzx.cart.service.impl.CartServiceImpl.getAllCkecked(CartServiceImpl.java:147)

针对service-cart微服务是获取不到当前登录用户的信息。

原因:service-order微服务调用service-cart微服务的时候,是通过openFeign进行调用,openFeign在调用的时候会丢失请求头

1.6.2 问题解决

解决方案:使用feign拦截器拦截请求,获取token,重新传递token

在这里插入图片描述

注意:为了让feign拦截器更加通用,那么此时可以将拦截器定义到common-service模块中

feign拦截器开发:

1、在common-service模块中加入openFeign的依赖

<!-- openfeign依赖 -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><scope>provided</scope>
</dependency>

2、定义feign拦截器

// com.atguigu.spzx.common.feign;
public class UserTokenFeignInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = requestAttributes.getRequest();String token = request.getHeader("token");requestTemplate.header("token" , token) ;}}

3、定义使用该拦截器的注解

// com.atguigu.spzx.common.anno;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.TYPE)
@Import(value = UserTokenFeignInterceptor.class)
public @interface EnableUserTokenFeignInterceptor {}

4、service-order微服务启动类上使用**@EnableUserTokenFeignInterceptor**注解

2 提交订单

2.1 需求说明

需求说明:用户在结算页面点击提交订单按钮,那么此时就需要保存订单信息(order_info)订单项信息(order_item)记录订单日志(order_log),成功后还需要清空订单对应的购物项,下单成功重定向到订单支付页面

查看接口文档:

下单接口地址及返回结果:

post /api/order/orderInfo/auth/submitOrder
参数:
{"orderItemList": [{"skuId": 6,"skuName": "小米 红米Note10 5G手机 颜色:黑色 内存:18G","thumbImg": "http://139.198.127.41:9000/spzx/20230525/665832167-1_u_1.jpg","skuPrice": 2999,"skuNum": 1},...],"userAddressId": 2,"feightFee": 0,"remark": "赶快发货"
}
返回结果(订单id){"code": 200,"message": "操作成功","data": 1
}

调用流程如下所示:

在这里插入图片描述

2.2 后端接口

2.2.1 查询用户地址

业务接口开发

操作模块:service-user

UserAddressController

表现层代码:

@Operation(summary = "获取地址信息")
@GetMapping("getUserAddress/{id}")
public UserAddress getUserAddress(@PathVariable Long id) {return userAddressService.getById(id);
}
UserAddressService

业务层代码实现:

//业务接口
UserAddress getById(Long id);//业务接口实现
@Override
public UserAddress getById(Long id) {return userAddressMapper.getById(id);
}
UserAddressMapper

持久层代码实现:

UserAddress getById(Long id);
UserAddressMapper.xml

在映射文件中定义对应的sql语句:

<select id="getById" resultMap="userAddressMap">select <include refid="columns" />from user_addresswhereid = #{id}
</select>

启动程序进行测试。

openFeign接口开发

步骤如下:

1、在spzx-service-client模块下创建一个service-user-client的子模块

2、在service-user-client模块下定义远程openFeign接口

// com.atguigu.spzx.feign.user;
@FeignClient(value = "service-user" , fallback = UserFeignClientFallback.class)
public interface UserFeignClient {@GetMapping("/api/user/userAddress/getUserAddress/{id}")public abstract Result<UserAddress> getUserAddress(@PathVariable Long id) ;}// com.atguigu.spzx.feign.user.fallback;
@Slf4j
public class UserFeignClientFallback implements UserFeignClient {@Overridepublic Result<UserAddress> getUserAddress(Long id) {log.info("UserFeignClientFallback...getUserAddress的方法执行了");return Result.build(null , ResultCodeEnum.SUCCESS) ;}}

3、降级类自动化配置

在resources目录下创建一个MATE-INF/spring文件夹,在该文件夹下创建一个

org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,文件的中的内容如下所示:

com.atguigu.spzx.feign.user.fallback.UserFeignClientFallback

4、修改service-order微服务

pom.xml文件中加入依赖:

<dependency><groupId>com.atguigu.spzx</groupId><artifactId>service-user-client</artifactId><version>1.0-SNAPSHOT</version>
</dependency>

启动类修改:

@EnableFeignClients(basePackages = {"com.atguigu.spzx.feign.cart","com.atguigu.spzx.feign.user"
})

2.2.2 业务接口开发

操作模块:service-order

OrderInfoDto

定义一个实体类用来封装下单的参数,具体定义如下所示

@Data
public class OrderInfoDto {//送货地址idprivate Long userAddressId;//运费private BigDecimal feightFee;//备注private String remark;//订单明细private List<OrderItem> orderItemList;
}
OrderLog

订单日志体类定义:

@Data
@Schema(description = "订单日志实体对象")
public class OrderLog extends BaseEntity {private static final long serialVersionUID = 1L;@Schema(description = "订单id")private Long orderId;@Schema(description = "操作人:用户;系统;后台管理员")private String operateUser;@Schema(description = "订单状态")private Integer processStatus;@Schema(description = "备注")private String note;}
OrderInfoController

表现层代码:

@Operation(summary = "提交订单")
@PostMapping("auth/submitOrder")
public Result<Long> submitOrder(@Parameter(name = "orderInfoDto", description = "请求参数实体类", required = true) @RequestBody OrderInfoDto orderInfoDto) {Long orderId = orderInfoService.submitOrder(orderInfoDto);return Result.build(orderId, ResultCodeEnum.SUCCESS);
}
OrderInfoService

业务层代码实现:

//业务接口
Long submitOrder(OrderInfoDto orderInfoDto);//业务接口实现
@Transactional
@Override
public Long submitOrder(OrderInfoDto orderInfoDto) {// 数据校验List<OrderItem> orderItemList = orderInfoDto.getOrderItemList();if (CollectionUtils.isEmpty(orderItemList)) {throw new GuiguException(ResultCodeEnum.DATA_ERROR);}for (OrderItem orderItem : orderItemList) {ProductSku productSku = productFeignClient.getBySkuId(orderItem.getSkuId()).getData();if(null == productSku) {throw new GuiguException(ResultCodeEnum.DATA_ERROR);}if(orderItem.getSkuNum().intValue() > productSku.getStockNum().intValue()) {throw new GuiguException(ResultCodeEnum.STOCK_LESS);}}// 构建订单数据,保存订单UserInfo userInfo = AuthContextUtil.getUserInfo();OrderInfo orderInfo = new OrderInfo();String orderNo = IdUtil.createSnowflake(1L, 1L).nextIdStr();orderInfo.setOrderNo(orderNo);orderInfo.setUserId(userInfo.getId());orderInfo.setNickName(userInfo.getUsername());UserAddress userAddress = userFeignClient.getUserAddress(orderInfoDto.getUserAddressId()).getData();orderInfo.setReceiverName(userAddress.getName());orderInfo.setReceiverPhone(userAddress.getPhone());orderInfo.setReceiverTagName(userAddress.getTagName());orderInfo.setReceiverProvince(userAddress.getProvinceCode());orderInfo.setReceiverCity(userAddress.getCityCode());orderInfo.setReceiverDistrict(userAddress.getDistrictCode());orderInfo.setReceiverAddress(userAddress.getFullAddress());BigDecimal totalAmount = new BigDecimal(0);for (OrderItem orderItem : orderItemList) {totalAmount = totalAmount.add(orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuNum())));}orderInfo.setTotalAmount(totalAmount);orderInfo.setCouponAmount(new BigDecimal(0));orderInfo.setOriginalTotalAmount(totalAmount);orderInfo.setFeightFee(orderInfoDto.getFeightFee());orderInfo.setPayType(2);orderInfo.setOrderStatus(0);orderInfoMapper.save(orderInfo);//保存订单明细for (OrderItem orderItem : orderItemList) {orderItem.setOrderId(orderInfo.getId());orderItemMapper.save(orderItem);}//记录日志OrderLog orderLog = new OrderLog();orderLog.setOrderId(orderInfo.getId());orderLog.setProcessStatus(0);orderLog.setNote("提交订单");orderLogMapper.save(orderLog);// TODO 远程调用service-cart微服务接口清空购物车数据return orderInfo.getId();
}

在ResultCodeEnum类添加枚举

STOCK_LESS( 219, "库存不足"),
Mapper接口

持久层代码实现:

OrderInfoMapper
@Mapper
public interface OrderInfoMapper {void save(OrderInfo orderInfo);
}
OrderItemMapper
@Mapper
public interface OrderItemMapper {void save(OrderItem orderItem);
}
OrderLogMapper
@Mapper
public interface OrderLogMapper {void save(OrderLog orderLog);
}
XML映射文件

在映射文件中定义对应的sql语句

OrderInfoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.atguigu.spzx.order.mapper.OrderInfoMapper"><resultMap id="orderInfoMap" type="com.atguigu.spzx.model.entity.order.OrderInfo" autoMapping="true"></resultMap><!-- 用于select查询公用抽取的列 --><sql id="columns">id,user_id,nick_name,order_no,coupon_id,total_amount,coupon_amount,original_total_amount,feight_fee,pay_type,order_status,receiver_name,receiver_phone,receiver_tag_name,receiver_province,receiver_city,receiver_district,receiver_address,payment_time,delivery_time,receive_time,remark,cancel_time,cancel_reason,create_time,update_time,is_deleted</sql><insert id="save" useGeneratedKeys="true" keyProperty="id">insert into order_info (id,user_id,nick_name,order_no,coupon_id,total_amount,coupon_amount,original_total_amount,feight_fee,pay_type,order_status,receiver_name,receiver_phone,receiver_tag_name,receiver_province,receiver_city,receiver_district,receiver_address,payment_time,delivery_time,receive_time,remark,cancel_time,cancel_reason) values (#{id},#{userId},#{nickName},#{orderNo},#{couponId},#{totalAmount},#{couponAmount},#{originalTotalAmount},#{feightFee},#{payType},#{orderStatus},#{receiverName},#{receiverPhone},#{receiverTagName},#{receiverProvince},#{receiverCity},#{receiverDistrict},#{receiverAddress},#{paymentTime},#{deliveryTime},#{receiveTime},#{remark},#{cancelTime},#{cancelReason})</insert>
</mapper>
OrderItemMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.atguigu.spzx.order.mapper.OrderItemMapper"><resultMap id="orderItemMap" type="com.atguigu.spzx.model.entity.order.OrderItem" autoMapping="true"></resultMap><!-- 用于select查询公用抽取的列 --><sql id="columns">id,order_id,sku_id,sku_name,thumb_img,sku_price,sku_num,create_time,update_time,is_deleted</sql><insert id="save" useGeneratedKeys="true" keyProperty="id">insert into order_item (id,order_id,sku_id,sku_name,thumb_img,sku_price,sku_num) values (#{id},#{orderId},#{skuId},#{skuName},#{thumbImg},#{skuPrice},#{skuNum})</insert>
</mapper>
OrderLogMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.atguigu.spzx.order.mapper.OrderLogMapper"><resultMap id="orderLogMap" type="com.atguigu.spzx.model.entity.order.OrderLog" autoMapping="true"></resultMap><!-- 用于select查询公用抽取的列 --><sql id="columns">id,order_id,operate_user,process_status,note,create_time,update_time,is_deleted</sql><insert id="save" useGeneratedKeys="true" keyProperty="id">insert into order_log (id,order_id,operate_user,process_status,note) values (#{id},#{orderId},#{operateUser},#{processStatus},#{note})</insert></mapper>

2.2.3 清空购物车

需求说明:订单生成成功以后,需要调用service-cart微服务的接口清空选中的购物车数据。

service-cart

在service-cart微服务中开发一个清空购物车的接口供service-order微服务进行调用:

CartController
// com.atguigu.spzx.cart.controller.CartController
@GetMapping(value = "/auth/deleteChecked")
public Result deleteChecked() {cartService.deleteChecked() ;return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
CartService
// com.atguigu.spzx.cart.service.impl.CartServiceImpl
@Override
public void deleteChecked() {Long userId = AuthContextUtil.getUserInfo().getId();String cartKey = getCartKey(userId);List<Object> objectList = redisTemplate.opsForHash().values(cartKey);       // 删除选中的购物项数据if(!CollectionUtils.isEmpty(objectList)) {objectList.stream().map(cartInfoJSON -> JSON.parseObject(cartInfoJSON.toString(), CartInfo.class)).filter(cartInfo -> cartInfo.getIsChecked() == 1).forEach(cartInfo -> redisTemplate.opsForHash().delete(cartKey , String.valueOf(cartInfo.getSkuId())));}
}
openFeign接口

在service-cart-client模块CartFeignClient中定义删除选中的购物车数据的远程接口方法:

// com.atguigu.spzx.feign.cart
@FeignClient(value = "service-cart" , fallback = CartFeignClientFallback.class)
public interface CartFeignClient {@GetMapping(value = "/api/order/cart/auth/deleteChecked")public abstract Result deleteChecked() ;}
service-order

改造service-order微服务的下单接口方法,添加清空选中购物车数据的远程调用代码:

// com.atguigu.spzx.order.service.impl.OrderInfoServiceImpl
@Transactional
@Override
public Long submitOrder(OrderInfoDto orderInfoDto) {// 1、数据校验// 2、构建订单数据,保存订单// 3、保存订单明细// 4、记录日志// 5、清空购物车数据cartFeignClient.deleteChecked() ;return orderInfo.getId();
}

3 支付页

3.1 需求说明

提交订单成功,跳转到支付页面,根据订单id获取订单详细信息,展示订单支付信息

查看接口文档:

根据订单id获取订单信息接口地址及返回结果:

get /api/order/orderInfo/auth/{orderId}
返回结果(订单id){"code": 200,"message": "成功","data": {"id": 194,"createTime": "2023-06-14 19:29:31","userId": 1,"nickName": "test","orderNo": "1686713371363","couponId": null,"totalAmount": 2999,"couponAmount": 0,"originalTotalAmount": 2999,"feightFee": 0,"payType": 2,"orderStatus": 0,"receiverName": "张三","receiverPhone": "15012563333","receiverTagName": "公司","receiverProvince": "130000","receiverCity": "130700","receiverDistrict": "130724","receiverAddress": "河北省张家口市沽源县快乐家园1号","paymentTime": null,"deliveryTime": null,"receiveTime": null,"remark": null,"cancelTime": null,"cancelReason": null}
}

3.2 后端接口

3.2.1 OrderInfoController

表现层代码:

@Operation(summary = "获取订单信息")
@GetMapping("auth/{orderId}")
public Result<OrderInfo> getOrderInfo(@Parameter(name = "orderId", description = "订单id", required = true) @PathVariable Long orderId) {OrderInfo orderInfo = orderInfoService.getOrderInfo(orderId);return Result.build(orderInfo, ResultCodeEnum.SUCCESS);
}

3.2.2 OrderInfoService

业务层代码实现:

//业务接口
OrderInfo getOrderInfo(Long orderId);//业务接口实现
@Override
public OrderInfo getOrderInfo(Long orderId) {return orderInfoMapper.getById(orderId);
}

3.2.3 OrderInfoMapper

持久层代码实现:

OrderInfo getById(Long orderId);

3.2.4 OrderInfoMapper.xml

在映射文件中定义对应的sql语句:

<select id="getById" resultMap="orderInfoMap">select <include refid="columns" />from order_infowhereid = #{id}
</select>

4 立即购买

4.1 需求说明

入口:商品详情页,点击“立即购买”按钮

立即购买直接进入结算页,不经过购物车,结算页返回数据与正常下单结算数据一致,提交订单接口不变,如图所示:

在这里插入图片描述

查看接口文档:

立即购买接口地址及返回结果:

get /api/order/orderInfo/auth/buy/{skuId}
返回结果:
{"code": 200,"message": "操作成功","data": {"totalAmount": 6997.00,"orderItemList": [{"skuId": 1,"skuName": "小米 红米Note10 5G手机 颜色:白色 内存:8G","thumbImg": "http://139.198.127.41:9000/spzx/20230525/665832167-5_u_1 (1).jpg","skuPrice": 1999.00,"skuNum": 2},...]}
}

4.2 后端接口

4.2.1 OrderInfoController

表现层代码:

@Operation(summary = "立即购买")
@GetMapping("auth/buy/{skuId}")
public Result<TradeVo> buy(@Parameter(name = "skuId", description = "商品skuId", required = true) @PathVariable Long skuId) {TradeVo tradeVo = orderInfoService.buy(skuId);return Result.build(tradeVo, ResultCodeEnum.SUCCESS);
}

4.2.2 OrderInfoService

业务层代码实现:

//业务接口
TradeVo buy(Long skuId);//业务接口实现
@Override
public TradeVo buy(Long skuId) {// 查询商品ProductSku productSku = productFeignClient.getBySkuId(skuId).getData();List<OrderItem> orderItemList = new ArrayList<>();OrderItem orderItem = new OrderItem();orderItem.setSkuId(skuId);orderItem.setSkuName(productSku.getSkuName());orderItem.setSkuNum(1);orderItem.setSkuPrice(productSku.getSalePrice());orderItem.setThumbImg(productSku.getThumbImg());orderItemList.add(orderItem);// 计算总金额BigDecimal totalAmount = productSku.getSalePrice();TradeVo tradeVo = new TradeVo();tradeVo.setTotalAmount(totalAmount);tradeVo.setOrderItemList(orderItemList);// 返回return tradeVo;
}

5 我的订单

5.1 需求说明

我的订单根据订单状态展示列表,如图所示:

在这里插入图片描述

查看接口文档:

我的订单接口地址及返回结果:

get /api/order/orderInfo/auth/{page}/{limit}?orderStatus={orderStatus}
返回结果:
{"code": 200,"message": "成功","data": {"total": 63,"list": [{"id": 194,"createTime": "2023-06-14 19:29:31","userId": 1,"nickName": "test","orderNo": "1686713371363","couponId": null,"totalAmount": 2999.00,"couponAmount": 0.00,"originalTotalAmount": 2999.00,"feightFee": 0.00,"payType": 2,"orderStatus": 0,"receiverName": "张三","receiverPhone": "15012563333","receiverTagName": "公司","receiverProvince": "130000","receiverCity": "130700","receiverDistrict": "130724","receiverAddress": "河北省张家口市沽源县快乐家园1号","paymentTime": null,"deliveryTime": null,"receiveTime": null,"remark": null,"cancelTime": null,"cancelReason": null,"orderItemList": [{"id": 428,"createTime": "2023-06-14 19:29:31","orderId": 194,"skuId": 6,"skuName": "小米 红米Note10 5G手机 颜色:黑色 内存:18G","thumbImg": "http://139.198.127.41:9000/spzx/20230525/665832167-1_u_1.jpg","skuPrice": 2999.00,"skuNum": 1}]},...],"pageNum": 1,"pageSize": 10,"size": 6,"startRow": 1,"endRow": 6,"pages": 7,"prePage": 0,"nextPage": 2,"isFirstPage": true,"isLastPage": false,"hasPreviousPage": false,"hasNextPage": true,"navigatePages": 10,"navigatepageNums": [1,2,3,4,5,6,7],"navigateFirstPage": 1,"navigateLastPage": 7}
}

5.2 后端接口

5.2.1 OrderInfoController

表现层代码:

@Operation(summary = "获取订单分页列表")
@GetMapping("auth/{page}/{limit}")
public Result<PageInfo<OrderInfo>> list(@Parameter(name = "page", description = "当前页码", required = true)@PathVariable Integer page,@Parameter(name = "limit", description = "每页记录数", required = true)@PathVariable Integer limit,@Parameter(name = "orderStatus", description = "订单状态", required = false)@RequestParam(required = false, defaultValue = "") Integer orderStatus) {PageInfo<OrderInfo> pageInfo = orderInfoService.findUserPage(page, limit, orderStatus);return Result.build(pageInfo, ResultCodeEnum.SUCCESS);
}

5.2.2 OrderInfoService

业务层代码实现:

//业务接口
PageInfo<OrderInfo> findUserPage(Integer page, Integer limit, Integer orderStatus);//业务接口实现
@Override
public PageInfo<OrderInfo> findUserPage(Integer page, Integer limit, Integer orderStatus) {PageHelper.startPage(page, limit);Long userId = AuthContextUtil.getUserInfo().getId();List<OrderInfo> orderInfoList = orderInfoMapper.findUserPage(userId, orderStatus);return new PageInfo<>(orderInfoList, limit);
}

5.2.3 OrderInfoMapper

持久层代码实现:

List<OrderInfo> findUserPage(Long userId, Integer orderStatus);

5.2.4 OrderInfoMapper.xml

在映射文件中定义对应的sql语句:

<resultMap id="orderInfoMap" type="com.atguigu.spzx.model.entity.order.OrderInfo" autoMapping="true"><!--id:表示主键 property:表示实体类的属性名 column:表示通过sql 执行以后查询出来的字段名--><id property="id" column="id"></id><!-- 一对多 --><collection property="orderItemList" ofType="com.atguigu.spzx.model.entity.order.OrderItem" autoMapping="true"column="{orderId = id}"select="com.atguigu.spzx.order.mapper.OrderItemMapper.findByOrderId"></collection>
</resultMap>
<select id="findUserPage" resultMap="orderInfoMap">select <include refid="columns" />from order_info<where><if test="userId != null">and user_id = #{userId}</if><if test="orderStatus != null">and order_status = #{orderStatus}</if>and is_deleted = 0</where>order by id desc
</select>

5.2.5 OrderInfo

订单实体添加属性:

@Schema(description = "订单项列表")
private List<OrderItem> orderItemList;

5.2.6 OrderItemMapper.xml

在映射文件中定义对应的sql语句:

<select id="findByOrderId" resultMap="orderItemMap">select <include refid="columns" />from order_itemwhereorder_id = #{orderId}and is_deleted = 0order by id desc
</select>

5.2.7 OrderItemMapper

持久层代码实现:

List<OrderItem> findByOrderId(Long orderId);

Mapper

持久层代码实现:

List<OrderInfo> findUserPage(Long userId, Integer orderStatus);

5.2.4 OrderInfoMapper.xml

在映射文件中定义对应的sql语句:

<resultMap id="orderInfoMap" type="com.atguigu.spzx.model.entity.order.OrderInfo" autoMapping="true"><!--id:表示主键 property:表示实体类的属性名 column:表示通过sql 执行以后查询出来的字段名--><id property="id" column="id"></id><!-- 一对多 --><collection property="orderItemList" ofType="com.atguigu.spzx.model.entity.order.OrderItem" autoMapping="true"column="{orderId = id}"select="com.atguigu.spzx.order.mapper.OrderItemMapper.findByOrderId"></collection>
</resultMap>
<select id="findUserPage" resultMap="orderInfoMap">select <include refid="columns" />from order_info<where><if test="userId != null">and user_id = #{userId}</if><if test="orderStatus != null">and order_status = #{orderStatus}</if>and is_deleted = 0</where>order by id desc
</select>

5.2.5 OrderInfo

订单实体添加属性:

@Schema(description = "订单项列表")
private List<OrderItem> orderItemList;

5.2.6 OrderItemMapper.xml

在映射文件中定义对应的sql语句:

<select id="findByOrderId" resultMap="orderItemMap">select <include refid="columns" />from order_itemwhereorder_id = #{orderId}and is_deleted = 0order by id desc
</select>

5.2.7 OrderItemMapper

持久层代码实现:

List<OrderItem> findByOrderId(Long orderId);

这篇关于day17_订单(结算,提交订单,支付页,立即购买,我的订单)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/790537

相关文章

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

HTML提交表单给python

python 代码 from flask import Flask, request, render_template, redirect, url_forapp = Flask(__name__)@app.route('/')def form():# 渲染表单页面return render_template('./index.html')@app.route('/submit_form',

Python3 BeautifulSoup爬虫 POJ自动提交

POJ 提交代码采用Base64加密方式 import http.cookiejarimport loggingimport urllib.parseimport urllib.requestimport base64from bs4 import BeautifulSoupfrom submitcode import SubmitCodeclass SubmitPoj():de

查看提交历史 —— Git 学习笔记 11

查看提交历史 查看提交历史 不带任何选项的git log-p选项--stat 选项--pretty=oneline选项--pretty=format选项git log常用选项列表参考资料 在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。 完成这个任务最简单而又有效的 工具是 git log 命令。 接下来的例子会用一个用于演示的 simplegit

form表单提交编码的问题

浏览器在form提交后,会生成一个HTTP的头部信息"content-type",标准规定其形式为Content-type: application/x-www-form-urlencoded; charset=UTF-8        那么我们如果需要修改编码,不使用默认的,那么可以如下这样操作修改编码,来满足需求: hmtl代码:   <meta http-equiv="Conte

js异步提交form表单的解决方案

1.定义异步提交表单的方法 (通用方法) /*** 异步提交form表单* @param options {form:form表单元素,success:执行成功后处理函数}* <span style="color:#ff0000;"><strong>@注意 后台接收参数要解码否则中文会导致乱码 如:URLDecoder.decode(param,"UTF-8")</strong></span>

husky 工具配置代码检查工作流:提交代码至仓库前做代码检查

提示:这篇博客以我前两篇博客作为先修知识,请大家先去看看我前两篇博客 博客指路:前端 ESlint 代码规范及修复代码规范错误-CSDN博客前端 Vue3 项目开发—— ESLint & prettier 配置代码风格-CSDN博客 husky 工具配置代码检查工作流的作用 在工作中,我们经常需要将写好的代码提交至代码仓库 但是由于程序员疏忽而将不规范的代码提交至仓库,显然是不合理的 所

js操作Dom节点拼接表单及ajax提交表单

有时候我们不希望html(jsp、vm)中有创建太多的标签(dom节点),所以这些任务都由js来做,下面提供套完整的表单提交流程,只需要在html中添加两个div其余的都由js来做吧。下面原生代码只需略微修改就能达到你想要的效果。 1、需要创建表单的点击事件 <a href="javascript:void(0);"onclick="changeSettleMoney('$!doctor.do

在幼儿园管理系统中,会议管理申请会议模块:添加会议记录(提交表单)的时候报:404错误!

在幼儿园管理系统(spring MVC)中,会议管理>申请会议模块:添加会议记录的时候报:404错误!不知道为啥找不到,一开始感觉一头雾水,怎么会出现404页面找不到错误那,又检查action,controller等这也没错啊!怎么出现404错误那。经过询问和查找,终于找到原因了。 原因是:添加的有时间字段。 代码: @InitBinder public void in