In this article, we are going to discuss on how to send SMS by exposing Rest endpoint using Apache Camel and SpringBoot with an example. And in the end, we can test whether it is working fine using SMPP Control Panel.

在本文中,我们将通过示例讨论如何通过使用Apache Camel和SpringBoot公开Rest端点来发送SMS。 最后,我们可以使用SMPP控制面板测试它是否工作正常。

First of all, I will give you a brief introduction to Apache Camel and SMPP.

首先,我将为您简要介绍Apache Camel和SMPP。

阿帕奇骆驼 (Apache Camel)

Apache Camel is an open-source Java framework that focuses on making integration easier and more accessible to developers. It does this by providing:

Apache Camel是一个开放源代码Java框架 ,致力于使集成更易于开发人员访问。 为此,它提供了:

  • Concrete implementations of all the widely used Enterprise Integration Patterns (EIPs)

    所有广泛使用的企业集成模式 (EIP)的具体实现

  • Connectivity to a great variety of transports and APIs

    连接到各种传输和API
  • Easy to use Domain-Specific Languages (DSLs) to wire EIPs and transports together.

    易于使用的领域特定语言(DSL)将EIP连接在一起并进行传输。

One of the fundamental principles of Camel is that it makes no assumptions about the type of data you need to process. This is an important point, because it gives you, the developer, an opportunity to integrate any kind of system, without the need of converting your data to a canonical format.

Camel的基本原则之一是,它不对您需要处理的数据类型做任何假设。 这一点很重要,因为它为开发人员提供了集成任何类型系统的机会,而无需将您的数据转换为规范格式。

SMPP协议 (SMPP Protocol)

The SMPP (Short Message Peer-to-Peer) protocol is an open, industry-standard protocol designed to provide a flexible data communications interface for the transfer of short message data between External Short Message Entities (ESME), Routing Entities (RE) and Message Centres (MC). It is a means by which applications can send SMS messages to mobile devices and receive SMS from mobile devices. This is done by using an SMPP connection with a Short Message Service Center (SMSC), SMS gateway (UK), SMPP gateway or hub. In this example, I will use SMPP Simulator to test the SMS sending process.

SMPP(短消息对等)协议是一种开放的行业标准协议,旨在为外部短消息实体(ESME),路由实体(RE)和外部实体之间的短消息数据传输提供灵活的数据通信接口。邮件中心(MC)。 这是应用程序可以将SMS消息发送到移动设备并从移动设备接收SMS的一种方式。 通过将SMPP连接与短消息服务中心(SMSC),SMS网关(UK),SMPP网关或集线器连接来完成。 在此示例中,我将使用SMPP Simulator测试SMS发送过程。

So Let’s Start.

因此,让我们开始吧。

First, we should create a spring project with below dependencies.

首先,我们应该创建一个具有以下依赖项的spring项目。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.2.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>smpp-camel</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>smpp-camel</name>
	<description>Demo project for Spring Boot</description>


	<properties>
		<java.version>8</java.version>
	</properties>


	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.camel.springboot</groupId>
			<artifactId>camel-spring-boot-starter</artifactId>
			<version>3.4.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-smpp</artifactId>
			<version>3.4.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-jackson</artifactId>
			<version>3.4.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-servlet</artifactId>
			<version>3.4.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.12</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

Here I have used the camel-servlet apache camel component which supports by Rest DSL(Domain Specific Language). If you want, there are more components you can use as an alternative(check here).

在这里,我使用了由Rest DSL(特定于域的语言)支持的camel-servlet apache camel组件。 如果需要,可以使用更多组件作为替代( 请在此处检查 )。

So After that, we should register the servlet configuration into a camel web configuration file. Although spring has its own configuration, it doesn’t configure this servlet automatically. Therefore if we don’t use this configuration it doesn’t detect any routes defined by us (returning a 404 error).

因此,在那之后,我们应该将servlet配置注册到骆驼Web配置文件中。 尽管spring具有自己的配置,但它不会自动配置该servlet。 因此,如果我们不使用此配置,它将不会检测到我们定义的任何路由(返回404错误)。

package com.example.demo;


import org.apache.camel.component.servlet.CamelHttpTransportServlet;


import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class CamelWebConfiguration {
    private static final String CAMEL_URL_MAPPING = "/v1/*";
    private static final String CAMEL_SERVLET_NAME = "CamelServlet";
    @Bean
    public ServletRegistrationBean servletRegistrationBean() {


        CamelHttpTransportServlet camelHttpTransportServlet = new CamelHttpTransportServlet();
        camelHttpTransportServlet.setAsync(true);


        ServletRegistrationBean registration = new ServletRegistrationBean
            (camelHttpTransportServlet,CAMEL_URL_MAPPING);
        registration.setName(CAMEL_SERVLET_NAME);


        return registration;
    }
}

So the next step is configuring SMPP. For that, we should define variables such as host, port, etc in the application.properties.

因此,下一步是配置SMPP。 为此,我们应该在application.properties中定义变量,例如host,port等。

smpp.tr.systemid=smppclient1
smpp.tr.host=localhost
smpp.tr.port=2775
smpp.tr.password=password
smpp.source.addr.ton=5
smpp.source.addr.npi=1
smpp.dest.addr.to=0
smpp.dest.addr.npi=0
smpp.dest.addr.ton=0
smpp.source.address=TEST
server.port=8085
server.contextPath=/sms-route

Now all the configurations are completed. let’s move to the implementation of the REST endpoint. For that, we should define a suitable model to which data to send through SMPP. So for that, I have implemented a simple message class with the sender and message-body.

至此所有配置完成。 让我们转到REST端点的实现。 为此,我们应该定义一个合适的模型,以便通过SMPP向其发送数据。 因此,我使用发件人和消息正文实现了一个简单的消息类。

package com.example.demo.dto;


public class Message {


    private int id;
    private int sender;
    private String messageBody;


    public void setId(int id){
        this.id = id;
    }
    public int getId(){
        return id;
    }
    public void setSender(int sender){
        this.sender = sender;
    }
    public int getSender(){
        return sender;
    }


    public void setMessageBody(String messageBody){
        this.messageBody = messageBody;
    }
    public String getMessageBody(){
        return messageBody;
    }


    public String toString(){
        return "sender "+ sender + "messageBody " + messageBody;
    }
}

There is an interesting feature used to implement the Event Driven Consumer and Message Translator patterns and to process message exchanges. That is the Processor Interface. If you use a Processor in a Camel route, then make sure to write the Processor in a thread-safe way, as the Camel routes can potentially be executed by concurrent threads, and therefore multiple threads can call the same Processor instance. So you can define a processor like the below example.

有一个有趣的功能用于实现事件驱动的使用者消息转换器模式,并处理消息交换。 那就是处理器接口。 如果在Camel路由中使用Processor,请确保以线程安全的方式编写Processor,因为Camel路由可能由并发线程执行,因此多个线程可以调用同一个Processor实例。 因此,您可以像以下示例一样定义处理器。

package com.example.demo.processor;


import com.example.demo.dto.Message;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


@Component("messageProcessor")
public class MessageProcessor implements Processor {


    @Override
    public void process(Exchange exchange) throws Exception{
        Message msg = exchange.getIn().getBody(Message.class);
        // do something with the msg and/or exchange here
        System.out.println(msg);


    }
}

Let’s move to implement the REST endpoint. First of all, we should create a class that extends RouterBuilder. Routebuilder is an abstract class. When implementing your own route, you usually extend from that RouteBuilder class (as the citation above already stated). As a consequence, you must implement the method configure() in which you implement the route. After that, we can define the routes and rest Configuration inside that. We can configure the binding mode globally on the rest configuration, and then override per rest service as well.

让我们开始实现REST端点。 首先,我们应该创建一个扩展RouterBuilder的类。 Routebuilder是一个抽象类。 当实现自己的路由时,通常从该RouteBuilder类扩展(如上文所述)。 因此,必须实现在其中实现路由的configure()方法。 之后,我们可以定义路由并在其中休息Configuration。 我们可以在其余配置上全局配置绑定模式,然后再覆盖每个其余服务。

To enable binding you configure this in Java DSL as shown below,

要启用绑定,您可以在Java DSL中对此进行配置,如下所示,

restConfiguration().component("servlet").bindingMode(RestBindingMode.json);

restConfiguration().component("servlet").bindingMode(RestBindingMode.json);

Here I have used the servlet component. So as I mentioned before, you can use netty-Http, camel-jetty, etc. But you have to configure those to project as I did in servlet. If we talk about RestBindingMode, there are 3 types. those are JSON, XML, and auto.

在这里,我使用了servlet组件。 因此,正如我之前提到的,您可以使用netty-Http,camel-jetty等。但是您必须像在servlet中一样配置它们以进行项目开发。 如果我们谈论RestBindingMode,则有3种类型。 这些是JSON,XML和自动。

When binding is enabled, Camel will bind the incoming and outgoing messages automatically, according to the content type of the message. If the message is JSON, then JSON binding happens and if the message is XML then XML binding happens. The binding happens for incoming and replies messages.

启用绑定后,Camel将根据邮件的内容类型自动绑定传入和传出的邮件。 如果消息是JSON,则发生JSON绑定;如果消息是XML,则发生XML绑定。 绑定发生在传入和回复消息中。

Other than the above options, there are more options such as defining a port, host and enabling client validation as well.

除上述选项外,还有更多选项,例如定义端口,主机和启用客户端验证。

Okay, let’s write a POST request to send a message.

好的,让我们编写一个POST请求来发送消息。

rest("/message")
.post("/add").consumes(MediaType.APPLICATION_JSON_VALUE).type
(Message.class).outType(Message.class)

So as I defined above, this post request should be work with below Url. We can check that using postman.

因此,正如我在上面定义的,此发布请求应与以下网址一起使用。 我们可以使用邮递员检查。

https://localhost:2775/v1/message/add

https:// localhost:2775 / v1 / message / add

type- to define the incoming type. (In this case message class which we defined above)

type-定义传入的类型。 (在这种情况下,我们上面定义的消息类)

outType-We can optionally define an outgoing type (which can be a good idea, to make it known from the DSL and also for tooling and JMX APIs to know both the incoming and outgoing types of the REST services.)

outType-我们可以选择定义一个传出类型(这是一个好主意,可以从DSL中得知它,也可以使工具和JMX API知道REST服务的传入和传出类型。)

After that, we can create a route using from and to. One route is created for each “from()” clause in DSL. A route is an artifact in Camel, and you could do certain administrative tasks towards it with the Camel API, such as start, stop, add, remove routes dynamically. The “to” clause is just an endpoint call.

之后,我们可以使用fromto创建一条路线 为DSL中的每个“ from()”子句创建一个路由。 路由是Camel中的工件,您可以使用Camel API对它执行某些管理任务,例如动态地启动,停止,添加,删除路由。 “ to”子句只是一个端点调用。

package com.example.demo;


import com.example.demo.dto.Message;
import com.example.demo.processor.MessageProcessor;
import org.apache.camel.BeanInject;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.rest.RestBindingMode;
import org.apache.camel.model.rest.RestParamType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;


@Component
public class SmsNotificationRouter extends RouteBuilder {


	@BeanInject
	private MessageProcessor messageProcessor;


	@Override
	public void configure() throws Exception {
		restConfiguration().component("servlet").bindingMode(RestBindingMode.json);


		rest("/message")
				.post("/add").consumes(MediaType.APPLICATION_JSON_VALUE).type(Message.class).outType(Message.class)
				.to("seda:newMessage");




		from("seda:newMessage?concurrentConsumers=20").routeId("smpp-sender").process(messageProcessor)
				.setHeader("CamelSmppDestAddr",simple("94${in.body.sender}"))
				.setBody(simple("${in.body.messageBody}"))
				.to("smpp://{{smpp.tr.systemid}}@{{smpp.tr.host}}:{{smpp.tr.port}}?password=
            {{smpp.tr.password}}&enquireLinkTimer=3000&transactionTimer=5000&sourceAddrTon={{smpp.source.addr.ton}}&sourceAddrNpi={{smpp.source.addr.npi}}&destAddrTon={{smpp.dest.addr.ton}}&destAddrNpi={{smpp.dest.addr.npi}}&sourceAddr={{smpp.source.address}}");


	}
}

This is the completed file with the SMPP configuration which we defined at the beginning. Here I Used Seda Component which provides asynchronous SEDA behavior. You can use alternatives such as direct. You can see many SMPP query parameters which I have used with this. There are 40 query parameters available in SMPP documentation (Seda Chart Query parameters).

这是我们开头定义的带有SMPP配置的完整文件。 在这里,我使用了提供异步SEDA行为的Seda组件。 您可以使用其他方法,例如直接。 您可以看到许多我使用过的SMPP查询参数。 SMPP文档中有40个查询参数( Seda图表查询参数 )。

Now all set for test message sending. So before Run the project you should turn on the SMPP Simulator. You can download a given zip file and run startsmppsim.sh file. now check the localhost:88 for SMPP Control Panel. You can see our control panel up and running as below image.

现在所有设置都准备发送测试消息。 因此,在运行项目之前,您应该打开SMPP Simulator 您可以下载给定的zip文件并运行startsmppsim.sh文件。 现在检查SMPP控制面板的localhost:88 。 您可以看到我们的控制面板启动并正在运行,如下图所示。

Image for post
SMPPSim Control panel
SMPPSim控制面板

Now we can test whether our application is working fine with sending a post request using postman. If it works fine, the InBoundQueue Size should be increased.

现在,我们可以测试我们的应用程序是否可以正常工作,可以使用邮递员发送邮寄请求。 如果工作正常,则应增加InBoundQueue Size

So that’s it. I hope you could learn something interesting from this article.

就是这样了。 希望您可以从本文中学到一些有趣的东西。

Thank You!

谢谢!

翻译自: https://medium.com/@pasindusenerath/exposing-rest-endpoint-to-send-sms-using-apache-camel-springboot-and-smpp-protocol-7f0ef53a5a55

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐