首页 > 其他分享 ># RocketMQ 实战:模拟电商网站场景综合案例(六)

# RocketMQ 实战:模拟电商网站场景综合案例(六)

时间:2024-06-11 23:32:37浏览次数:17  
标签:实战 SHOP false itheima import 电商 com public RocketMQ

RocketMQ 实战:模拟电商网站场景综合案例(六)

一、RocketMQ 实战 :项目公共类介绍

1、ID 生成器 :IDWorker:Twitter 雪花算法。

在 shop-common 工程模块中,IDWorker.java 是 ID 生成器公共类,运用 Twitter 雪花算法,自动生成项目 ID,而不会存在重复现象。


package com.itheima.utils;

public class IDWorker {

    /**
     * 起始的时间戳
     */
    private final static long START_STMP = 1480166465631L;

    /**
     * 每一部分占用的位数
     */
    private final static long SEQUENCE_BIT = 12; //序列号占用的位数
    private final static long MACHINE_BIT = 5;   //机器标识占用的位数
    private final static long DATACENTER_BIT = 5;//数据中心占用的位数

    /**
     * 每一部分的最大值
     */
    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);

    /**
     * 每一部分向左的位移
     */
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;

    private long datacenterId;  //数据中心
    private long machineId;     //机器标识
    private long sequence = 0L; //序列号
    private long lastStmp = -1L;//上一次时间戳

    public IDWorker(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    /**
     * 产生下一个ID
     *
     * @return
     */
    public synchronized long nextId() {
        long currStmp = getNewstmp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStmp == lastStmp) {
            //相同毫秒内,序列号自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //不同毫秒内,序列号置为0
            sequence = 0L;
        }

        lastStmp = currStmp;

        return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
                | datacenterId << DATACENTER_LEFT       //数据中心部分
                | machineId << MACHINE_LEFT             //机器标识部分
                | sequence;                             //序列号部分
    }

    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStmp) {
            mill = getNewstmp();
        }
        return mill;
    }

    private long getNewstmp() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        IDWorker idWorker = new IDWorker(2, 3);
        for (int i = 0; i < 10; i++) {
            System.out.println(idWorker.nextId());
        }
    }

}

在这里插入图片描述

2、异常处理类:

在 shop-common 工程模块中,
CustomerException.java :自定义异常公共类,CastException.java :异常抛出公共类。

package com.itheima.exception;

import com.itheima.constant.ShopCode;
import lombok.extern.slf4j.Slf4j;

/**
 * 异常抛出类
 */
@Slf4j
public class CastException {
    public static void cast(ShopCode shopCode) {
        log.error(shopCode.toString());
        throw new CustomerException(shopCode);
    }
}


package com.itheima.exception;

import com.itheima.constant.ShopCode;

/**
 * 自定义异常
 */
public class CustomerException extends RuntimeException{

    private ShopCode shopCode;

    public CustomerException(ShopCode shopCode) {
        this.shopCode = shopCode;
    }
}

3、常量类 : ShopCode:系统状态类

在 shop-common 工程模块中,ShopCode.java :是系统状态公共类。


package com.itheima.constant;

/**
 * @author Think
 */

public enum ShopCode {
    //正确
    SHOP_SUCCESS(true, 1, "正确"),
    //错误
    SHOP_FAIL(false, 0, "错误"),

    //付款
    SHOP_USER_MONEY_PAID(true, 1, "付款"),
    //退款
    SHOP_USER_MONEY_REFUND(true, 2, "退款"),
    //订单未确认
    SHOP_ORDER_NO_CONFIRM(false, 0, "订单未确认"),
    //订单已确认
    SHOP_ORDER_CONFIRM(true, 1, "订单已经确认"),
    //订单已取消
    SHOP_ORDER_CANCEL(false, 2, "订单已取消"),
    //订单已取消
    SHOP_ORDER_INVALID(false, 3, "订单无效"),
    //订单已取消
    SHOP_ORDER_RETURNED(false, 4, "订单已退货"),
    //订单已付款
    SHOP_ORDER_PAY_STATUS_NO_PAY(true,0,"订单未付款"),
    //订单已付款
    SHOP_ORDER_PAY_STATUS_PAYING(true,1,"订单正在付款"),
    //订单已付款
    SHOP_ORDER_PAY_STATUS_IS_PAY(true,2,"订单已付款"),
    //消息正在处理
    SHOP_MQ_MESSAGE_STATUS_PROCESSING(true, 0, "消息正在处理"),
    //消息处理成功
    SHOP_MQ_MESSAGE_STATUS_SUCCESS(true, 1, "消息处理成功"),
    //消息处理失败
    SHOP_MQ_MESSAGE_STATUS_FAIL(false, 2, "消息处理失败"),
    //请求参数有误
    SHOP_REQUEST_PARAMETER_VALID(false, -1, "请求参数有误"),
    //优惠券已经使用
    SHOP_COUPON_ISUSED(true, 1, "优惠券已经使用"),
    //优惠券未使用
    SHOP_COUPON_UNUSED(false, 0, "优惠券未使用"),
    //快递运费不正确
    SHOP_ORDER_STATUS_UPDATE_FAIL(false, 10001, "订单状态修改失败"),
    //快递运费不正确
    SHOP_ORDER_SHIPPINGFEE_INVALID(false, 10002, "订单运费不正确"),
    //订单总价格不合法
    SHOP_ORDERAMOUNT_INVALID(false, 10003, "订单总价格不正确"),
    //订单保存失败
    SHOP_ORDER_SAVE_ERROR(false, 10004, "订单保存失败"),
    //订单确认失败
    SHOP_ORDER_CONFIRM_FAIL(false, 10005, "订单确认失败"),
    //商品不存在
    SHOP_GOODS_NO_EXIST(false, 20001, "商品不存在"),
    //订单价格非法
    SHOP_GOODS_PRICE_INVALID(false, 20002, "商品价格非法"),
    //商品库存不足
    SHOP_GOODS_NUM_NOT_ENOUGH(false, 20003, "商品库存不足"),
    //扣减库存失败
    SHOP_REDUCE_GOODS_NUM_FAIL(false, 20004, "扣减库存失败"),
    //库存记录为空
    SHOP_REDUCE_GOODS_NUM_EMPTY(false, 20005, "扣减库存失败"),
    //用户账号不能为空
    SHOP_USER_IS_NULL(false, 30001, "用户账号不能为空"),
    //用户信息不存在
    SHOP_USER_NO_EXIST(false, 30002, "用户不存在"),
    //余额扣减失败
    SHOP_USER_MONEY_REDUCE_FAIL(false, 30003, "余额扣减失败"),
    //已经退款
    SHOP_USER_MONEY_REFUND_ALREADY(true, 30004, "订单已经退过款"),
    //优惠券不不存在
    SHOP_COUPON_NO_EXIST(false, 40001, "优惠券不存在"),
    //优惠券不合法
    SHOP_COUPON_INVALIED(false, 40002, "优惠券不合法"),
    //优惠券使用失败
    SHOP_COUPON_USE_FAIL(false, 40003, "优惠券使用失败"),
    //余额不能小于0
    SHOP_MONEY_PAID_LESS_ZERO(false, 50001, "余额不能小于0"),
    //余额非法
    SHOP_MONEY_PAID_INVALID(false, 50002, "余额非法"),
    //Topic不能为空
    SHOP_MQ_TOPIC_IS_EMPTY(false, 60001, "Topic不能为空"),
    //消息体不能为空
    SHOP_MQ_MESSAGE_BODY_IS_EMPTY(false, 60002, "消息体不能为空"),
    //消息发送失败
    SHOP_MQ_SEND_MESSAGE_FAIL(false,60003,"消息发送失败"),
    //支付订单未找到
    SHOP_PAYMENT_NOT_FOUND(false,70001,"支付订单未找到"),
    //支付订单已支付
    SHOP_PAYMENT_IS_PAID(false,70002,"支付订单已支付"),
    //订单付款失败
    SHOP_PAYMENT_PAY_ERROR(false,70002,"订单支付失败");


    Boolean success;
    Integer code;
    String message;

    ShopCode() {

    }

    ShopCode(Boolean success, Integer code, String message) {
        this.success = success;
        this.code = code;
        this.message = message;
    }

    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return "ShopCode{" +
                "success=" + success +
                ", code=" + code +
                ", message='" + message + '\'' +
                '}';
    }
}

4、响应实体类 :Result:封装响应状态和响应信息

在 shop-pojo 工程模块中,Result.java :是封装响应状态和响应信息的公共类。

package com.itheima.entity;

import java.io.Serializable;

/**
 * 结果实体类
 */
public class Result implements Serializable {
    private Boolean success;
    private String message;

    public Result() {
    }

    public Result(Boolean success, String message) {
        this.success = success;
        this.message = message;
    }

    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return "Result{" +
                "success=" + success +
                ", message='" + message + '\'' +
                '}';
    }
}

二、RocketMQ 实战:模拟电商网站场景综合案例 – 下单功能时序图

在这里插入图片描述

三、RocketMQ 实战:下单接口定义和编码步骤分析

1、下单基本流程:接口定义 IOrderService.java

在 shop-api 工程模块中,创建 IOrderService.java 下单接口类。


package com.itheima.api;

import com.itheima.entity.Result;
import com.itheima.shop.pojo.TradeOrder;

public interface IOrderService {

    /**
     * 下单接口
     * @param order
     * @return
     */
    public Result confirmOrder(TradeOrder order);

}

2、下单基本流程:业务类实现 OrderServiceImpl.java

在 shop-order-service 工程模块中,创建 OrderServiceImpl.java 业务实现类。
基本框架如下:


@Slf4j
@Component
@Service(interfaceClass = IOrderService.class)
public class OrderServiceImpl implements IOrderService {

    @Override
    public Result confirmOrder(TradeOrder order) {
        //1.校验订单
       
        //2.生成预订单
       
        try {
            //3.扣减库存
            
            //4.扣减优惠券
           
            //5.使用余额
           
            //6.确认订单
            
            //7.返回成功状态
           
        } catch (Exception e) {
            //1.确认订单失败,发送消息
            
            //2.返回失败状态
        }

    }
}

四、RocketMQ 实战:模拟电商网站场景综合案例–校验订单流程分析图

在这里插入图片描述

五、RocketMQ 实战:模拟电商网站场景综合案例–校验订单实现

1、在 shop-order-service 工程模块中,创建 OrderServiceImpl.java 下单业务类,

完成 订单校验方法。


package com.itheima.shop.service;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.itheima.api.ICouponService;
import com.itheima.api.IGoodsService;
import com.itheima.api.IOrderService;
import com.itheima.api.IUserService;
import com.itheima.constant.ShopCode;
import com.itheima.entity.MQEntity;
import com.itheima.entity.Result;
import com.itheima.exception.CastException;
import com.itheima.shop.mapper.TradeOrderMapper;
import com.itheima.shop.pojo.*;
import com.itheima.utils.IDWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;

@Slf4j
@Component
@Service(interfaceClass = IOrderService.class)
public class OrderServiceImpl implements IOrderService {


    @Reference
    private IGoodsService goodsService;

    @Reference
    private IUserService userService;

    @Override
    public Result confirmOrder(TradeOrder order) {
        //1.校验订单
        checkOrder(order);
        //2.生成预订单
       
        try {
            //3.扣减库存
     
            //4.扣减优惠券
     
            //5.使用余额

            //6.确认订单
          
            //7.返回成功状态
            
        } catch (Exception e) {
            //1.确认订单失败,发送消息
    

            //2.返回订单确认失败消息
     
            return null;
        }
    }


    /**
     * 校验订单
     *
     * @param order
     */
    private void checkOrder(TradeOrder order) {
        //1.校验订单是否存在
        if (order == null) {
            CastException.cast(ShopCode.SHOP_ORDER_INVALID);
        }
        //2.校验订单中的商品是否存在
        TradeGoods goods = goodsService.findOne(order.getGoodsId());
        if (goods == null) {
            CastException.cast(ShopCode.SHOP_GOODS_NO_EXIST);
        }
        //3.校验下单用户是否存在
        TradeUser user = userService.findOne(order.getUserId());
        if (user == null) {
            CastException.cast(ShopCode.SHOP_USER_NO_EXIST);
        }
        //4.校验商品单价是否合法
        if (order.getGoodsPrice().compareTo(goods.getGoodsPrice()) != 0) {
            CastException.cast(ShopCode.SHOP_GOODS_PRICE_INVALID);
        }
        //5.校验订单商品数量是否合法
        if (order.getGoodsNumber() >= goods.getGoodsNumber()) {
            CastException.cast(ShopCode.SHOP_GOODS_NUM_NOT_ENOUGH);
        }
        log.info("校验订单通过");
    }
}


2、在 shop-api 工程模块中,创建 IGoodsService.java 接口类。


package com.itheima.api;

import com.itheima.entity.Result;
import com.itheima.shop.pojo.TradeGoods;
import com.itheima.shop.pojo.TradeGoodsNumberLog;

public interface IGoodsService {
    /**
     * 根据ID查询商品对象
     * @param goodsId
     * @return
     */
    TradeGoods findOne(Long goodsId);


}


3、在 shop-api 工程模块中,创建 IUserService.java 接口类。


package com.itheima.api;

import com.itheima.entity.Result;
import com.itheima.shop.pojo.TradeUser;
import com.itheima.shop.pojo.TradeUserMoneyLog;

public interface IUserService {
    TradeUser findOne(Long userId);

    Result updateMoneyPaid(TradeUserMoneyLog userMoneyLog);
}


4、在 shop-user-service 工程模块中,创建 UserServiceImpl.java 实现类。


package com.itheima.shop.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.api.IUserService;
import com.itheima.constant.ShopCode;
import com.itheima.entity.Result;
import com.itheima.exception.CastException;
import com.itheima.shop.mapper.TradeUserMapper;
import com.itheima.shop.mapper.TradeUserMoneyLogMapper;
import com.itheima.shop.pojo.TradeUser;
import com.itheima.shop.pojo.TradeUserMoneyLog;
import com.itheima.shop.pojo.TradeUserMoneyLogExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;

@Component
@Service(interfaceClass = IUserService.class)
public class UserServiceImpl implements IUserService{

    @Autowired
    private TradeUserMapper userMapper;

    @Autowired
    private TradeUserMoneyLogMapper userMoneyLogMapper;

    @Override
    public TradeUser findOne(Long userId) {
        if(userId==null){
            CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);
        }
        return userMapper.selectByPrimaryKey(userId);
    }


}


5、在 shop-goods-service 工程模块中,创建 GoodsServiceImpl.java 实现类。


package com.itheima.shop.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.api.IGoodsService;
import com.itheima.constant.ShopCode;
import com.itheima.entity.Result;
import com.itheima.exception.CastException;
import com.itheima.shop.mapper.TradeGoodsMapper;
import com.itheima.shop.mapper.TradeGoodsNumberLogMapper;
import com.itheima.shop.pojo.TradeGoods;
import com.itheima.shop.pojo.TradeGoodsNumberLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
@Service(interfaceClass = IGoodsService.class)
public class GoodsServiceImpl implements IGoodsService {

    @Autowired
    private TradeGoodsMapper goodsMapper;

    @Autowired
    private TradeGoodsNumberLogMapper goodsNumberLogMapper;

    @Override
    public TradeGoods findOne(Long goodsId) {
        if (goodsId == null) {
            CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);
        }
        return goodsMapper.selectByPrimaryKey(goodsId);
    }

}

上一节关联链接请点击:
# RocketMQ 实战:模拟电商网站场景综合案例(五)

标签:实战,SHOP,false,itheima,import,电商,com,public,RocketMQ
From: https://blog.csdn.net/qfyh_djh/article/details/139575441

相关文章

  • python pywinauto自动化实战案例:输入账号密码及点击登录按钮
    代码示例在使用pywinauto来模拟输入账号密码及点击登录按钮时,你需要先定位到相应的输入框和按钮,然后执行相应的操作。以下是一个基本的示例代码,展示如何实现这一过程:frompywinautoimportApplicationimporttime#假设你的应用已经启动,如果是启动应用的话,使用.start(......
  • 【机器学习】Qwen2大模型原理、训练及推理部署实战
    目录​​​​​​​一、引言二、模型简介2.1Qwen2 模型概述2.2Qwen2 模型架构三、训练与推理3.1Qwen2 模型训练3.2Qwen2 模型推理四、总结一、引言刚刚写完【机器学习】Qwen1.5-14B-Chat大模型训练与推理实战 ,阿里Qwen就推出了Qwen2,相较于Qwen1.5中0.5B......
  • 书生·浦语大模型实战营 第八节课 微调弱智吧(如果AI可以正确回答弱智吧的所有问题,人类
    读前感:第四节课也进行了简单的微调,但最终微调出来个傻子,这次再试试,看看如何进行改善。实际的应用场景中使用微调的应该不会特别多,毕竟开源大模型并不是小公司可以玩得起的。对于小公司,真正的微调有哪些场景呢?欢迎大家讨论。读后感:本节课是整个训练营的最后一份笔记。希望......
  • Go变量作用域精讲及代码实战
    关注作者,复旦AI博士,分享AI领域与云服务领域全维度开发技术。拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕博,复旦机器人智能实验室成员,国家级大学生赛事评审专家,发表多篇SCI核心期刊学术论文,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI产品研发负责......
  • 《Windows核心编程》若干知识点实战应用分享
    目录1、进程的虚拟内存分区与小于0x10000的小地址内存区1.1、进程的虚拟内存分区1.2、小于0x10000的小地址内存区2、保存线程上下文的CONTEXT结构体3、从汇编代码角度去理解多线程运行过程的典型实例4、调用TerminateThread强制结束线程会导致线程中的资源没有释放的问题......
  • 老玩家BJL百家三珠路打法及技巧----实战技巧总结篇
    更多技巧可移步围脖—老晨谈赌​​三珠路打法由来已久,因其简单实用,很多人都会用到。什么叫三珠路,就是把大路庄闲,按三个一组进行划分,找一个路单图片,按水平和垂直排列。把牌路按照三珠路排列后,样式如下图:每一列为一个图形,会出现8种图形:如果按照前面的统计数据,那么以下......
  • 【网络安全】CTF_AWD实战速胜指南,《AWD特训营》
    前言【文末送书】今天推荐一本网安领域优质书籍《AWD特训营》,本文将从其内容与优势出发,详细阐发其对于网安从业人员的重要性与益处。正文本书适用于以下读者:网络安全爱好者网络安全从业人员企业IT运维人员信息安全及相关专业的大学生随着网络安全问题日益凸显,国家......
  • 微信小程序毕业设计-外卖点餐系统项目开发实战(附源码+演示视频+LW)
    大家好!我是岛上程序猿,感谢您阅读本文,欢迎一键三连哦。......
  • 老晨谈赌详解AG百家和BJL下三路的实战技巧打法个人经验
    更多技巧可移步围脖【老晨谈赌】技术可以通过学习来获得,经验可以通过实战来得到,心态可以通过调节来增强。每一个人都不是生来都无比强大的,我也是如此,也是通过无数个黑夜的煎熬最后才研究出来的,所以如果说幸运,我们都幸运,如果说不幸运,我们其实都一样。可以不设置止盈点,但是你一......
  • OpenCV实战案例——直线检测[C++]
    0.前言本文以实战案例为背景,一步步讲述如何使用计算机图像处理相关知识提取图片中英语填空题答题线。1.需求背景某公司打算设计一款英语题目批改APP,要求学生上传英语填空题图片,然后该APP自动标注答题线位置(使用红线标注),方便后续定位和批改答案。下图(图1-1)为某一学生上传的......