rabbitmq延时队列实现电商延未支付取消订单---java版

应用场景:用户下单未支付,需要系统自动取消订单
解决方案:
1,实现定时器轮询订单,将未支付满30分钟后的订单,进行更新状态,变为取消订单
2,用户查看订单时,先将之前未支付的订单进行更新为取消订单
3,延时队列实现取消订单
ps:还有其它方案,一时想不起来了


优缺点:
方案一:
优点:实现简单
缺点:轮询太消耗资源了,数据库说- -噢顶木住啦
方案二:
优点:实现简了,如果不需要下单减库存或者锁库存操作,该方案实用。
缺点:下单时已经锁定了库存,简单说,如果不取消订单,库存就一直被锁。老板说》你走人吧
方案三:
优点:好用!!!!

代码实现:

连接类:

public class RabbitmqConfiguration {

    private final String SERVER_HOST="127.0.0.1";//rabbitmq 服务器地址
    private final int PORT=5672;//端口号
    private final String USER_NAME="guest";//用户名
    private final String PASSWORD="guest";//密码
    private final boolean QUEUE_SAVE =true;//队列是否持久化
    private final String MESSAGE_SAVE = "1" ;//消息持久化  1,0
    //rabbitmq 连接工厂
    private final ConnectionFactory RAB_FACTORY = new ConnectionFactory();

    private Connection connection;

    public void init() throws Exception{
            RAB_FACTORY.setHost(SERVER_HOST);
            RAB_FACTORY.setPort(PORT);
            RAB_FACTORY.setUsername(USER_NAME);
            RAB_FACTORY.setPassword(PASSWORD);
            RAB_FACTORY.setVirtualHost("/");
            this.connection = RAB_FACTORY.newConnection();
    }
    public Connection getConnection() {
        return connection;
    }

    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    public boolean isQUEUE_SAVE() {
        return QUEUE_SAVE;
    }

    public String getMESSAGE_SAVE() {
        return MESSAGE_SAVE;
    }
}

生产者:

/**
 *
 * 提供延时队列发送方法
 */

public class MQOrderOverTimeQueue {

    private static final Logger log= LoggerFactory.getLogger(MQOrderOverTimeQueue.class);


    private RabbitmqConfiguration rabConf;

    //队列名称
    //****==================订单延时队列=======================*****//
    //订单延时队列
    public final String DELAY_QUEUE_NAME = "delay-queue-orderOverTime";
    //订单延时队列死信交换的交换器名称
    public final String EXCHANGENAME = "exchange-orderOverTime";
    //订单延时队列死信的交换器路由key
    public final String ROUTINGKEY = "routingKey-orderOverTime";

    private Channel delayChannel;//延时队列连接通道

    private Channel consumerChannel;//消费队列连接通道

    public void init() throws Exception{
        //创建连接通道
        delayChannel=rabConf.getConnection().createChannel();

        delayChannel.confirmSelect();//开启confirm事务

        /**创建处理延时消息的延时队列*/
        Map  arg = new HashMap ();
        //配置死信交换器
        arg.put("x-dead-letter-exchange",EXCHANGENAME); //交换器名称
        //死信交换路由key (交换器可以将死信交换到很多个其他的消费队列,可以用不同的路由key 来将死信路由到不同的消费队列去)
        arg.put("x-dead-letter-routing-key", ROUTINGKEY);
        delayChannel.queueDeclare(DELAY_QUEUE_NAME, rabConf.isQUEUE_SAVE(), false, false, arg);

    }

    /**
     * 方法描述: 发送延迟订单处理消息
     * @param msg 消息内容 (订单号或者json格式字符串)
     * @param overTime 消息存活时间
     * @throws Exception
     */
    public void sendMessage(String msg,Long overTime) throws Exception{
        AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
                .expiration(overTime.toString()) //设置消息存活时间(毫秒)
                .build();
        delayChannel.basicPublish("",DELAY_QUEUE_NAME, properties, msg.getBytes("UTF-8"));

        if (delayChannel.waitForConfirms()){
            log.info("send success");
        }else{
            log.info("send false");
        }
    }



    public RabbitmqConfiguration getRabConf() {
        return rabConf;
    }


    public void setRabConf(RabbitmqConfiguration rabConf) {
        this.rabConf = rabConf;
    }

    public MQOrderOverTimeQueue() {
        RabbitmqConfiguration rf= new RabbitmqConfiguration();
        try {
            rf.init();
            this.rabConf = rf;
            this.init();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

消费者:

**
 * 延时队列接收,项目启动时,会默认启动
 */

@Component
public class MQOrderOverTimeRecv {

    private static final Logger log=LoggerFactory.getLogger(MQOrderOverTimeRecv.class);

    private RabbitmqConfiguration rabConf;


    @Resource
    private ShopOrderMapper shopOrderMapper;

    @Resource
    private ShopGoodsSpecidMapper shopGoodsSpecidMapper;

    //队列名称
    //****==================订单延时队列=======================*****//
    //订单延时队列
    public final String DELAY_QUEUE_NAME = "delay-queue-orderOverTime";
    //订单延时消费队列
    public final String CONSUME_QUEUE_NAME = "consume-queue-orderOverTime";
    //订单延时队列死信交换的交换器名称
    public final String EXCHANGENAME = "exchange-orderOverTime";
    //订单延时队列死信的交换器路由key
    public final String ROUTINGKEY = "routingKey-orderOverTime";

    private Channel consumerChannel;//消费队列连接通道

    public void init() throws Exception{
        //创建连接通道
       // delayChannel=rabConf.getConnection().createChannel();
        consumerChannel=rabConf.getConnection().createChannel();

        //创建交换器
        consumerChannel.exchangeDeclare(EXCHANGENAME,"direct");

        /**创建消费队列*/
        consumerChannel.queueDeclare(CONSUME_QUEUE_NAME, rabConf.isQUEUE_SAVE(), false, false, null);
        //参数1:绑定的队列名  参数2:绑定至哪个交换器  参数3:绑定路由key
        consumerChannel.queueBind(CONSUME_QUEUE_NAME, EXCHANGENAME,ROUTINGKEY);
        //最多接受条数 0为无限制,每次消费消息数(根据实际场景设置),true=作用于整channel,false=作用于具体的消费者
        consumerChannel.basicQos(0,10, false);

        //创建消费队列的消费者
        Consumer consumer = new DefaultConsumer(consumerChannel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,AMQP.BasicProperties properties, byte[] body)
                    throws IOException  {
                String message = new String(body, "UTF-8");
                try {
                    //业务逻辑处理
                    ConsumeMessage(message);
                    //确认消息已经消费  参数2(true=设置后续消息为自动确认消费  false=为手动确认)
                    consumerChannel.basicAck(envelope.getDeliveryTag(), false);
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        boolean flag=false;//是否手动确认消息  true 是  false否
        consumerChannel.basicConsume(CONSUME_QUEUE_NAME, flag, consumer);
    }


    /**
     *
     * 方法描述:监听队列consume-queue-orderOverTime中的消息,用于更新商品订单
     * 业务逻辑说明: TODO(总结性的归纳方法业务逻辑)
     * @param msg 消费消息(订单号,或特定格式json字符串)
     * @throws InterruptedException
     */
    public void ConsumeMessage(String msg) throws InterruptedException {
       		sout("处理业务”);
        }
    }


    public RabbitmqConfiguration getRabConf() {
        return rabConf;
    }


    public void setRabConf(RabbitmqConfiguration rabConf) {
        this.rabConf = rabConf;
    }


}

------------------------------------------------------------上文出自胖胖,转载请附带原文链接

后续更新自学的方法,以及java知识总结.
如果想交流自学可以加我微信(15979939343).
我是哪怕前路坎坷,也不愿负年轻的菜狗,自学之路,共勉。

你可能感兴趣的:(java自学,java,中间件)