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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/732424.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NIFI从Oracle11G同步数据到Mysql_亲测可用_解决数据重复_数据跟源表不一致的问题---大数据之Nifi工作笔记0065

首先来看一下整体的流程: 可以看到了用到了上面的这些处理器,然后我们主要看看,这里之前 同步的时候,总是出现重复的数据,奇怪. 比如源表中只有166条数据,但是同步过去以后变成了11万条数据了. ${db.table.name:equals(table1):or(${db.table.name:equals(table2)})} 可以看…

【精选好刊】JCR2区SCI仅17天上线见刊,最后10篇版面!

录用案例 JCR2区地质环境类SCI&EI (进展顺) 【期刊简介】IF&#xff1a;3.0-4.0&#xff0c;JCR2区&#xff0c;中科院3/4区&#xff1b; 【检索情况】SCI&EI双检&#xff1b; 【征稿领域】地球观测、环境监测和管理相关或结合研究均可&#xff1b; 【案例分享】重…

前端面试练习24.3.8

防抖和节流 防抖&#xff08;Debouncing&#xff09;&#xff1a; 防抖是指在短时间内连续触发同一事件时&#xff0c;只执行最后一次触发的事件处理函数。 在实际应用中&#xff0c;常常用于处理用户输入的搜索框或者滚动事件。例如&#xff0c;当用户连续输入搜索关键词时&am…

业务代码中如何使用装饰器模式?

装饰器模式&#xff08;Decorator Pattern&#xff09;介绍 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;我们可以动态地给一个对象添加额外的职责。而不是通过继承增加子类的方式来扩展对象的功能&#xff0c;装饰器模式使用组合的…

[N1CTF 2018]eating_cms 不会编程的崽

题倒是不难&#xff0c;但是实在是恶心到了。 上来就是登录框&#xff0c;页面源代码也没什么特别的。寻思抓包看一下&#xff0c;数据包直接返回了sql查询语句。到以为是sql注入的题目&#xff0c;直到我看到了单引号被转义。。。挺抽象&#xff0c;似乎sql语句过滤很严格。又…

Java基础知识点之思维导图

一、走进Java编程世界 二、变量常量和运算符 三、if选择结构 四、switch选择结构 五、while循环结构 六、for循环结构 七、数组 八、类与对象 九、深入循环结构 十、类的无参方法 十一、类的带参方法 十二、字符串

读已提交隔离级别下竟然有间隙锁

业务背景 广告主痛点的为进行一次全媒体联合投放&#xff0c;若投放10个媒体&#xff0c;需要制作和上传10个创意、50张不同尺寸和出血区要求的图片和视频素材、近100个元素&#xff0c;投放成本极高。这也是制约部分用户使用新产品投放的原因。 因此进行升级。以三个创意为例…

Prometheus添加nginx节点显示不支持stub_status 解决办法

1、我们在使用Prometheus监控添加nginx节点监控的时候&#xff0c;在被监控节点的nginx配置文件中添加下面的模块 server { listen 80; server_name localhost; location /stub_status { stub_status on; access_log off; …

微服务技术栈SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式(四):消息队列MQ

文章目录 一、消息队列MQ二、RabbitMQ2.1 单机部署2.2 消息模型 三、SpringAMAP3.1 简单消息队列3.2 工作消息队列3.3 发布-订阅模型&#xff1a;FanoutExchange 广播交换机3.4 发布-订阅模型&#xff1a;DirectExchange 路由交换机3.5 发布-订阅模型&#xff1a;TopicExchange…

Day29:安全开发-JS应用DOM树加密编码库断点调试逆向分析元素属性操作

目录 JS原生开发-DOM树-用户交互 JS导入库开发-编码加密-逆向调试 思维导图 JS知识点&#xff1a; 功能&#xff1a;登录验证&#xff0c;文件操作&#xff0c;SQL操作&#xff0c;云应用接入&#xff0c;框架开发&#xff0c;打包器使用等 技术&#xff1a;原生开发&#x…

推房子游戏c++

这段代码是一个推箱子游戏的实现。游戏中有一个地图&#xff0c;地图上有墙壁、人、箱子和目标位置。玩家通过键盘输入WASD或方向键来控制人物的移动&#xff0c;目标是将所有的箱子推到相应的目标位置上。 代码中的dt数组表示地图&#xff0c;每个位置上的字符表示对应的元素…

c语言在线聊天室

c语言基于tcp和多线程的在线聊天室(c语言通讯系统)功能需求 1.实现多线程 2.构建socke套接字实现一对一通信 3.实现多个电脑的通信 4.数据传输加密和解密 5.多人实时聊天 6.具备群聊和私聊的功能 实现原理: 服务端公网Ip暴露,客户端端口随机分配,通过服务端公网IP连接,服务端…

【开源】SpringBoot框架开发免税店商城管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.2 研究方法 三、系统展示四、核心代码4.1 查询免税种类4.2 查询物品档案4.3 新增顾客4.4 新增消费记录4.5 审核免税 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的免税店商城管理系…

【文本编辑】Typora v1.8.6 绿色版

下载地址 Typora v1.8.6 绿色版 简介 Typora 是一款简洁、直观的跨平台 Markdown 编辑器&#xff0c;旨在提供优雅的写作体验。与传统的 Markdown 编辑器不同&#xff0c;Typora 提供所见即所得的编辑界面&#xff0c;使用户可以即时预览 Markdown 文档的渲染效果&#xff0…

prometheus 原理(架构,promql表达式,描点原理)

大家好&#xff0c;我是蓝胖子&#xff0c;提到监控指标&#xff0c;不得不说prometheus&#xff0c;今天这篇文章我会对prometheus 的架构设计&#xff0c;promql表达式原理和监控图表的绘图原理进行详细的解释。来让大家对prometheus的理解更加深刻。 架构设计 先来看看&am…

性能测试干2年,还不会这个技术点?

nmon是一种在AIX与各种Linux操作系统上广泛使用的监控与分析工具&#xff0c;记录的信息比较全面&#xff0c;结合nmon_analyzer工具产生数据文件与图形化结果。 nmon可监控的数据类型 内存使用情况、磁盘适配器、文件系统中的可用空间、CPU使用率等等数据信息 特点 ①占用…

Java零基础-数组的访问和遍历

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一个人虽可以走的更快&#xff0c;但一群人可以走的更远。 我是一名后…

使用CSS制作动态的环形图/饼图

使用纯 CSS Animation conic-gradient 实现一个环形图。 饼图的实现思路和环形图一样&#xff0c;去掉中间的圆形遮盖 after 伪类元素即可。 一、构建基础样式 构建圆形节点和中间的遮盖元素。 <style>body {background-color: rgb(130, 226, 255);}.circle {top: 16…

持续更新 | 与您分享 Flutter 2024 年路线图

作者 / Michael Thomsen Flutter 是一个拥有繁荣社区的开源项目&#xff0c;我们致力于确保我们的计划公开透明&#xff0c;并将毫无隐瞒地分享从问题到设计规范的所有内容。我们了解到许多开发者对 Flutter 的功能路线图很感兴趣。我们往往会在一年中不断更改并调整这些计划&a…

Clock Verification IP

Clock Verification IP IP 参数及接口 IP 例化界面 相关函数 start_clock //产生时钟 <hierarchy_path>.IF.start_clockstop_clock //停止时钟 <hierarchy_path>.IF.stop_clockset_initial_value //设置时钟初始值为 0 <hierarchy_path>IF.set_initia…