SpringCloud+SpringBoot 项目搭建 (四) RocketMq

本篇文章接上一篇:SpringCloud+SpringBoot 项目搭建 (三) MyBatis-Push

SpringCloud+SpringBoot 项目搭建 (四) RocketMq

1. 安装RocketMq环境

下载RocketMq

http://rocketmq.apache.org/release_notes/release-notes-4.3.0/

选择
在这里插入图片描述
解压后配置环境变量(根据个人路径自行配置)

cmd进去文件路径bin文件夹中开启服务:

启动NAMESERVER
start mqnamesrv.cmd
启动BROKER
start mqbroker.cmd -n 127.0.0.1:9876 autoCreateTopicEnable=true

出现两个界面
在这里插入图片描述
代表启动成功
注意:两个服务命令框不能关闭

2. 安装RocketMQ插件

git下载

https://github.com/apache/rocketmq-externals.git
或
git://github.com/apache/rocketmq-externals.git
或
https://gitee.com/mirrors/RocketMQ-Externals.git
哪个有速度下载哪个

修改插件项目配置
修改rocketmq-console模块下的application.properties

#启动项目的插件项目的端口
server.port=8520 
#BROKER配置的端口
rocketmq.config.namesrvAddr=http://127.0.0.1:9876

回到rocketmq-console路径执行maven打包命令
mvn clean package -Dmaven.test.skip=true

mvn clean package -Dmaven.test.skip=true

进入target执行打包好的jar(注意看下打包的版本号)

java -jar rocketmq-console-ng-2.0.0.jar

浏览器打开配置的启动插件端口测试
在这里插入图片描述
至此RocketMQ的环境与插件配置完成

3.项目集成RocketMq

老规矩引入pom,注意版本号要和刚才上面配置的服务版本号一致

			<rocketmq.version>4.3.0</rocketmq.version>
 			<dependency>
                <groupId>org.apache.rocketmq</groupId>
                <artifactId>rocketmq-client</artifactId>
                <version>${rocketmq.version}</version>
            </dependency>

创建商品和订单表用来测试

CREATE TABLE `product` (
  `id` varchar(32) NOT NULL COMMENT '商品id',
  `name` varchar(255) DEFAULT NULL COMMENT '商品名称',
  `inventory` int(11) DEFAULT NULL COMMENT '库存',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `order` (
  `id` varchar(255) NOT NULL COMMENT '订单id',
  `product_id` varchar(255) DEFAULT NULL COMMENT '商品id',
  `user` bigint(20) DEFAULT NULL COMMENT '用户id',
  `number` int(11) DEFAULT NULL COMMENT '数量',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO product (id,`name`,inventory) values (1,'测试商品1',100)
INSERT INTO product (id,`name`,inventory) values (2,'测试商品2',100)
INSERT INTO product (id,`name`,inventory) values (3,'测试商品3',100)

创建代码生成器生成model,mapper,service
在这里插入图片描述
在这里插入图片描述
创建一个生成订单的service和controller

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    OrderService orderService;
    /**
     * 测试下单
     */
    @GetMapping("/create")
    public Object createOrderDoc( String productId, Integer number, Long userId) {
        Order order = orderService.create(productId,number,userId);
        return order;
    }
}


@Log4j2
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Resource
    OrderMapper orderMapper;
    @Resource
    private DefaultMQProducer defaultMQProducer;
    @Override
    public Order create(String productId,Integer number, Long userId) {
        //创建订单
        Order order = new Order();
        order.setId((new Random().nextInt(10000))+"");
        order.setNumber(number);
        order.setUser(userId);
        order.setProductId(productId);
        int insert = orderMapper.insert(order);
        //模拟发送短信通过MQ消费者来发送
        Map<String,Object> map = new HashMap<>();
        map.put("orderId",order.getId());
        map.put("message","创建订单");
        Message message = new Message(GlobalConstant.TOPIC, "Tag1", "CreateOrder",JSONObject.toJSONString(map).getBytes());
        // 这里用到了这个mq的异步处理,类似ajax,可以得到发送到mq的情况,并做相应的处理
        //不过要注意的是这个是异步的
        try {
            defaultMQProducer.send(message, new SendCallback() {
                @Override
                public void onSuccess(SendResult sendResult) {
                    log.info("传输成功");
                    log.info(JSONObject.toJSON(sendResult));
                }
                @Override
                public void onException(Throwable e) {
                    log.error("传输失败", e);
                }
            });
        } catch (MQClientException e) {
            e.printStackTrace();
        } catch (RemotingException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return insert>0?order:null;
    }
}

配置生产者config

spring.application.name=springcloud
rocketmq.producer.groupName=${spring.application.name}
rocketmq.producer.namesrvAddr=127.0.0.1:9876
rocketmq.producer.default=false

注意:上面的namesrvAddr地址需要和上面启动服务的地址一致

@Component
@Getter
@Setter
@ConfigurationProperties(prefix = "rocketmq.producer")
@Configuration
@ToString
public class ProducerConfig {
    private String namesrvAddr;
    private String groupName;
}

@Slf4j
@Configuration
@EnableConfigurationProperties(ProducerConfig.class)
public class MqConfiguration {
	@Autowired
	ProducerConfig producerConfig;
	@Bean
	public DefaultMQProducer defaultMQProducer() throws MQClientException {
		DefaultMQProducer defaultMQProducer = new DefaultMQProducer(producerConfig.getGroupName());
		defaultMQProducer.setNamesrvAddr(producerConfig.getNamesrvAddr());
		defaultMQProducer.setVipChannelEnabled(false);
		defaultMQProducer.setRetryTimesWhenSendAsyncFailed(10);
		defaultMQProducer.start();
		log.info("rocketmq producer server开启成功---------------------------------.");
		return defaultMQProducer;
	}
}

配置消费者

@Slf4j
@Component
public class MessageMQ {
    /**
     * 消费者实体对象
     */
    private DefaultMQPushConsumer consumer;
    @Autowired
    MessageService messageService;
    /**
     * 通过构造函数 实例化对象
     */
    public MessageMQ() throws MQClientException {
        consumer = new DefaultMQPushConsumer(GlobalConstant.groupName);
        consumer.setNamesrvAddr(GlobalConstant.namesrvAddr);
        //消费模式:一个新的订阅组第一次启动从队列的最后位置开始消费 后续再启动接着上次消费的进度开始消费
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        //订阅主题和 标签(*代表所有标签)下信息
        consumer.subscribe(GlobalConstant.TOPIC, "*");
        //注册消费的监听 并在此监听中消费信息,并返回消费的状态信息
        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
            // msgs中只收集同一个topic,同一个tag,并且key相同的message会把不同的消息分别放置到不同的队列中
            try {
                for (Message msg : msgs) {
                    //消费者获取消息 这里只输出 不做后面逻辑处理
                    String body = new String(msg.getBody(), "utf-8");
                    log.info("Consumer-获取消息-主题topic为={}, 消费消息为={}", msg.getTopic(), body);
                    JSONObject object = JSONObject.parseObject(body);
                    if("CreateOrder".equals(msg.getKeys())){
                        messageService.send(object.getString("orderId"));
                    }
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return ConsumeConcurrentlyStatus.RECONSUME_LATER;
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });
        consumer.start();
        System.out.println("消费者 启动成功=======");
    }
}

编写测试发送消息方法

public interface MessageService {
    boolean send(String orderId);
}
@Log4j2
@Service
public class MessageServiceImpl implements MessageService {
    @Override
    public boolean send(String orderId) {
        log.info("发送短信-------"+orderId+"------------");
        return true;
    }
}

访问controller验证
在这里插入图片描述
插件控制器查看
在这里插入图片描述
至此RocketMQ就简单的集成到系统中

4.填坑

1.TOPIC一般是服务器设置好 而不能在代码里去新建topic( 如果没有创建好,生产者往该主题发送消息 会报找不到topic错误)
所以需要去控制器创建
在这里插入图片描述
2.namesrvAddr必须和启动BROKER 127.0.0.1:9876中配置一样,注意仔细
3.创建环境变量中 路径中请勿有中文和空格!路径中请勿有中文和空格!路径中请勿有中文和空格!重要的事情说三遍 包括Program Files中的空格

下一篇:SpringCloud+SpringBoot 项目搭建 (五) Feign

posted @ 2021-04-13 00:57  rr完美'诺言  阅读(47)  评论(0编辑  收藏  举报  来源