背景
物联网比较核心的就是处理上报,并处理不同协议的问题。当然没有通用的思路,只有适合业务的场景。
http适用
mqtt不做相关,相关设备都是适用http协议做出数据发送。
url与handlerFilter配置
不使用controller配置对url路径进行管理。
其实和使用controller是同一种效果,使用controller也是需要策略模式,对不同协议进行处理。
配置需要用到HttpRequestHandlingMessagingGateWay。
HttpRequestHandlingMessagingGateWay 源码文档解释中,可以直接注册为bean。 同理serverlet
可以处理请求信息。
实现HttpRequstHandler接口。
HttpRequestHandlerServlet
public class HttpRequestHandlerServlet extends HttpServlet {
@Nullable
private HttpRequestHandler target;
@Override
public void init() throws ServletException {
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
this.target = wac.getBean(getServletName(), HttpRequestHandler.class);
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Assert.state(this.target != null, "No HttpRequestHandler available");
LocaleContextHolder.setLocale(request.getLocale());
try {
this.target.handleRequest(request, response);
}
catch (HttpRequestMethodNotSupportedException ex) {
String[] supportedMethods = ex.getSupportedMethods();
if (supportedMethods != null) {
response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", "));
}
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, ex.getMessage());
}
finally {
LocaleContextHolder.resetLocaleContext();
}
}
}
然后是配置代码
@Bean
public HttpRequestHandlingMessagingGateway networkingOrganizationExtendInbound() {
return HttpInboundGatewayBuilder.newInstance().pathPatterns(
ProtocolUrlEnum.COMPANY_EXTEND.URI).httpMethod(HttpMethod.POST).requestPayloadType(SzdAccessDataDTO.class)
.requestChannel(this.szdOrganizationExtendMessageRequestChannel)
.errorChannel(this.szdHttpGlobalErrorChannel).build();
}
pathPatterns指定路径,相当于requestMapping中的value
requstPayLoadType指定消息体的实例化类型
requestChannel定义消息处理通道
errorChannel出错后消息处理通道
private DirectChannel szdBaseMessageChannelbuild() {
DirectChannel channel = new DirectChannel();
// 权限拦截
channel.addInterceptor(this.permissionInterceptor);
// 平台对接状态
channel.addInterceptor(this.dockingStatusInterceptor);
// 消息包体大小拦截
channel.addInterceptor(this.packetSizeInterceptor);
// 绑定消息所属消息协议
channel.addInterceptor(this.protocolInterceptor);
// HTTP接入数据处理链
channel.subscribe(this.szdhttpRequestHandlerChain);
return channel;
}
spring-Integration现在使用的确实比较少。相关文章也较少。spring实战第六版中对相应组件有所介绍。
interceptor 实现ChannelInterceptor接口就可以
subscribe()方法需要传入httpHandler
public MessageHandlerChain szdhttpRequestHandlerChain() {
// 创建消息处理链类
MessageHandlerChain chain = new MessageHandlerChain();
// 消息处理类集合
List<MessageHandler> handlers = new ArrayList<>();
// 原数据平台编号填充处理器
handlers.add(this.szdFillPlatformCodeActivator);
// 消息响应处理器
handlers.add(this.szdHttpResponseActivator);
chain.setHandlers(handlers);
return chain;
}
这里使用MessageHandlerChain集成一下
添加的两个Activator 为框架基础的服务激活器。可以将消息发送给handler实现。
@Bean
public ServiceActivatingHandler szdHttpResponseActivator(MessageChannel rawDataMsgChannel,
ProtocolContext protocolContext) {
SzdSyncProtocolCheckRespProcessor processor =
new SzdSyncProtocolCheckRespProcessor(rawDataMsgChannel, protocolContext);
return new ServiceActivatingHandler(processor);
}
代码中是再次创建了一个通道,spring-intergration本身就是为集成流的处理方案。
一开始配置了一个通道,是http接受请求的通道,此时在通道内再次集成另一个通道.
@Bean
public DirectChannel rawDataMsgChannel(AccessDataCountInterceptor accessDataCountInterceptor,
AccessDataCovertToJsonInterceptor accessDataCovertToJsonInterceptor, @Qualifier("rawDataKafkaOutbound") MessageHandler rawDataKafkaOutbound) {
DirectChannel channel = new DirectChannel();
channel.addInterceptor(accessDataCountInterceptor);
channel.addInterceptor(accessDataCovertToJsonInterceptor);
channel.subscribe(rawDataKafkaOutbound);
return channel;
}
跟前面的代码异曲同工,并再次subscribe 一个kafka消息通道.
@Bean
public KafkaProducerMessageHandler<String, String> rawDataKafkaOutbound(
KafkaTemplate<String, String> kafkaTemplate) {
KafkaProducerMessageHandler<String, String> handler =
new KafkaProducerMessageHandler<>(kafkaTemplate);
// 将发送失败的消息发送到失败通道
handler.setSendFailureChannel(this.rawDataSendToKafkaFailureChannel);
return handler;
}
如何发送到响应的kafka Topic
KafkaProducerMessageHandler 有相应说明
producerRecord = createProducerRecord(message);
MessageHeaders messageHeaders = message.getHeaders();
String topic = this.topicExpression != null ?
this.topicExpression.getValue(this.evaluationContext, message, String.class)
: messageHeaders.get(KafkaHeaders.TOPIC, String.class);
if (topic == null) {
topic = this.kafkaTemplate.getDefaultTopic();
}
这个只能
所以设置kafka topic需要在请求体的请求头中设置 KafakaHeader.TOPIC
集成流从通道流转完成。
集成流 入站协议和出站协议都可以自行配置,处理的多了,就多几个handler.
还有自定义xml,作为协议模板的这次写不完了,打包出bug, 一直在解决。
结束,下班。假期愉快。