实现tars-springboot-ibm-mq的微服务(微服务系列第二天)

前言

学习JAVA第2天 目标实现: 基于tars springboot ibm mq的微服务

第1天学习了java的项目创建,打包,上传到tars中,收获良多,今天折腾一下项目中需要用到的IBM MQ消息服务,于是就实现了基于tars springboot ibm mq的微服务.

搭建IBM MQ

同样还是使用docker来创建,添加ibmmq

$ docker volume create qm1data  # ibm mq 有些权限要求,配置不当有可能启动不了,所以使用卷的方式比较简单

docker-compose.yml 中添加内容如下:

  ibmmq:
    image: ibmcom/mq
    container_name: ibmmq
    volumes:
      - qm1data:/mnt/mqm
    environment:
      LICENSE: "accept"
      MQ_QMGR_NAME: "QM1"
      MQ_APP_PASSWORD: "abcd1234"
    ports:
      - "1414:1414"
      - "9443:9443"
    networks:
      tars:
        ipv4_address: 172.25.0.201

volumes:
  qm1data:
   

另外给node一个web服务端口,后续会用上

  node:
    # image: tarscloud/tars-node:stable
    image: tarscloud/tars-node:latest
    container_name: tars-node
    # restart: always
    ports:
      - "1080:1080"
    networks:
      tars:
        ipv4_address: 172.25.0.5
    volumes:
      - ./node/data:/data/tars:rw
      - /etc/localtime:/etc/localtime
    environment:
      INET: eth0
      WEB_HOST: http://172.25.0.3:3000
    depends_on:
      - framework

运行起来

$ docker-compose up -d

Creating tars-mysql ... done
Creating ibmmq      ... done
Creating tars-framework ... done
Creating tars-node      ... done

打开浏览器访问一下,并做相应的配置 https://localhost:9443 重要!!! 9443是SSL端口,一定需要使用https来访问,好像ibmmq这个版本的web服务有bug,重启Docker后,会占用端口,之后就启动不了了,原因没有深究,测试的话,默认创建好后就可以使用,要不要Web管理端都无所谓。

IBM MQ登录页

输入账号密码登录,默认账号密码是: admin/passw0rd

IBM MQ登录后的欢迎页

版本信息

新版本的IBM MQ的界面还是很漂亮的

测试IBM MQ

添加ibmmq的依赖

pom.xml

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
		</dependency>
		<dependency>
			<groupId>com.ibm.mq</groupId>
			<artifactId>mq-jms-spring-boot-starter</artifactId>
			<version>2.4.2</version>
		</dependency>

添加配置项

application.properties spring boot 默认都是开启8080端口,因为我开发机上要运行多个,所以改下端口。

# tomcat default 8080
server.port=1080

# ibm mq config
ibm.mq.queueManager=QM1
ibm.mq.channel=DEV.APP.SVRCONN
ibm.mq.connName=172.25.0.201(1414)
ibm.mq.user=app
ibm.mq.password=abcd1234
ibm.mq.sendQueueName=DEV.QUEUE.1
ibm.mq.recvQueueName=DEV.QUEUE.1

修改main

TarsMqServerApplication 这里需要用到spring boot 的web服务,所以这里恢复到项目初始状态,上传tars时,协议选非tars协议即可。

@SpringBootApplication
@EnableTarsServer
public class TarsMqServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(TarsMqServerApplication.class, args);
	}

}

添加Rest控制器

这里先做个简单的测试,主要目的是用最简单的代码测试ibmmq的连通性 src/main/java/com/example/tarsmqserver/web/MQController.java

@RestController
@EnableJms
@RequestMapping("/api/mq")
public class MQController { 
    @Autowired
	private JmsTemplate jmsTemplate;

	@GetMapping("send") 
	String send() {
		try {
			jmsTemplate.convertAndSend("DEV.QUEUE.1", "Hello World!");
			return "OK";
		} catch (JmsException ex) {
			ex.printStackTrace();
			return "FAIL";
		}
	}

	@GetMapping("recv")
	String recv() {
		try {
			return jmsTemplate.receiveAndConvert("DEV.QUEUE.1").toString();
		} catch (JmsException ex) {
			ex.printStackTrace();
			return "FAIL";
		}
	}
    
}

提交tars-web测试

打包

$ mvn clean package -DskipTests 

上传

上传办法详细看第1节

测试

$ curl http://localhost:1080/api/mq/recv
Hello World!%

$ curl http://localhost:1080/api/mq/send
OK%

看到上面的信息,证明IBM MQ服务正常跑起来了,jms测试代码也起了作用,后面就是改良代码了。

JMS

服务介绍

关于JMS到网上抄了一份作业,了解一下运行逻辑。 下面开始打造基于tars的JMS服务了

ibmmq 绑定配置文件

目录建得比较随意,网上抄作业看到有人用这种目录方式,就直接抄了。 src/main/java/com/example/tarsmqserver/domain/JmqConfig.java

@Component
public class JmqConfig {

    @Value("${ibm.mq.sendQueueName}")
    private String sendQueueName;

    @Value("${ibm.mq.recvQueueName}")
    private  String recvQueueName;


    public String getSendQueueName() {
        return sendQueueName;
    }

    public String getRecvQueueName(){
        return recvQueueName;
    }

}

消息生产者

src/main/java/com/example/tarsmqserver/service/mqserver/Producer.java

@Service("producer")
@EnableJms
public class Producer {
    /**
     * 也可以注入JmsTemplate,JmsMessagingTemplate对JmsTemplate进行了封装
     */
    @Autowired
    private JmsMessagingTemplate jmsTemplate;

    /**
     * 发送消息,destinationName 是IBM MQ 发送队列的名称,message是待发送的消息
     *
     * @param destinationName
     * @param message
     */
    public boolean sendMessage(String destinationName, String message) {
        boolean ok = false;
        try {
            jmsTemplate.convertAndSend(destinationName, message);
            ok = true;
        } catch (JmsException ex) {
            ex.printStackTrace();
            ok = false;
        }
        return ok;
    }
}

消息消费者

src/main/java/com/example/demo/jmq/ConsumerListener.java

@Component
public class ConsumerListener extends MessageListenerAdapter {
    private static Logger logger = LoggerFactory.getLogger(ConsumerListener.class);

    /**
     * 使用JmsListener配置消费者监听的队列
     * 
     * @param receivedMsg 接收到的消息
     */
    @JmsListener(destination = "#{@conf.recvQueueName}")
    public void receiveQueue(String receivedMsg) {
        logger.info("Consumer收到的报文为: {}", receivedMsg);
    }

    @Bean
    public JmqConfig conf() {
        return new JmqConfig();
    }
}

默认入口

关闭本地tomcat服务,只开启rpc服务端口 src/main/java/com/example/demo/DemoApplication.java

@SpringBootApplication
@EnableTarsServer
public class TarsMqServerApplication {

	public static void main(String[] args) {
		// 关闭 spring boot 自带的web服务 目前场景只用到了rpc服务
		SpringApplication app = new SpringApplication(TarsMqServerApplication.class);
		app.setWebApplicationType(WebApplicationType.NONE);
		app.run(args);
	}
}

完善tars接口

用的是上一章定义的接口 tars接口定义传送门 第1天 通过docker整合springboot和tars src/main/java/com/example/tarsmqserver/service/mqserver/impl/MessageServantImpl.java

@TarsServant("messageObj")
@Component
public class MessageServantImpl implements MessageServant {
    @Autowired
    private Producer producer;

    @Autowired
    private JmqConfig jmqConfig;

    private final static Logger MSG_LOGGER = LoggerFactory.getLogger("msg");

    /**
     * 发送消息到IBM MQ
     */
    @Override
    public boolean send(String msg) {
        
        if (StringUtils.isBlank(msg)) {
            return false;
        }

        String queueName = jmqConfig.getSendQueueName();
        MSG_LOGGER.info("send: {} -> {}", queueName, msg);
        return producer.sendMessage(queueName, msg);
    }

    @Override
    public boolean encode(String sign, Holder<String> enStr) {
        // TODO 先简单走流程 后面实现具体加密签名之类的
        if (StringUtils.isBlank(sign)) {
            return false;
        }
        enStr.setValue("123" + sign + "456");
        MSG_LOGGER.info("encode: {} -> {}", sign, enStr.value);
        return true;
    }

    @Override
    public boolean encodeWithSend(String msg, String sign) {
        if (StringUtils.isBlank(msg) || StringUtils.isBlank(sign)) {
            return false;
        }

        Holder<String> enStr = new Holder<String>();
        boolean ok = encode(sign, enStr);
        if (!ok) {
            return false;
        }
        return send(enStr.value + msg);
    }
}

这里的字符串验证工具用的是org.apache.commons,maven引入如下

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.11</version>
		</dependency>

生成jar包/上传/测试/观察

$ mvn clean package -DskipTests

查看日志,有类似信息

2021-01-29 13:14:34.416 INFO 4474 --- [enerContainer-1] c.e.t.service.mqserver.ConsumerListener : Consumer收到的报文为: 123中文456aaaaaaaaaaaaaaa
2021-01-29 13:14:56.194 INFO 4474 --- [enerContainer-1] c.e.t.service.mqserver.ConsumerListener : Consumer收到的报文为: 春树暮云

整合完成

汇总

最后项目目录

$ tree
.
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── tarsmqserver
    │   │               ├── TarsMqServerApplication.java
    │   │               ├── domain
    │   │               │   └── JmqConfig.java
    │   │               ├── service
    │   │               │   └── mqserver
    │   │               │       ├── ConsumerListener.java
    │   │               │       ├── MessageServant.java
    │   │               │       ├── Producer.java
    │   │               │       └── impl
    │   │               │           └── MessageServantImpl.java
    │   │               └── web
    │   │                   └── MQController.java
    │   └── resources
    │       ├── application.properties
    │       └── mqserver.tars

源代码

学习JAVA第2天 实现tars-springboot-ibm-mq的微服务(微服务系列第二天)

结语

由于才接触java,springboot很多功能都是通过java专有的注解完成的。学习时间有限,很多东西还没有理解,中间调试的时候花了不少时间去查资料和调试。更因为我是使用vscode+tars+springboot来弄的,发生了错误也不知道哪里出问题了。搜索的资料只能做参考,然后自己消化学习,最终调试完成。