当前位置: 首页>后端>正文

Camel组件-Rest组件

Rest组件简介

rest组件可以用于开发restful接口、发起接口请求调用等。其作用等同于spring mvc + rest template。在学习过程中可以类比这两个库来学习。类比spring mvc的功能,后续用接口开发来表达;类比rest template的功能,后续用接口调用来表述。


Camel组件-Rest组件,第1张
rest组件使用

开发指南

spring boot项目中引入相关依赖

<dependency>
  <groupId>org.apache.camel.springboot</groupId>
  <artifactId>camel-rest-starter</artifactId>
  <version>x.x.x</version>
  <!-- use the same version as your Camel core version -->
</dependency>

使用eeif框架的直接引入framework-idp即可

接口定义

基本使用格式如下:

语法:
rest:method:path[:uriTemplate]?[options]

示例:
<from uri="rest:get:/v1/user/info:{userId}?host={{app.server.info}}"/>

method支持9种请求方式get, post, put, delete, patch, head, trace, connect, options,在rest ful接口定义中通常使用get, post, put, delete。
path定义遵循rest规范包括路径/请求参数/路径参数的定义规范。请求header、请求body遵循eip整体语法,可以直接在流程中定义。

上面定义好的接口路径 最终的访问地址如下

http(s)://{ip:port}/{contextPath}/{camelContextPath}/v1/user/info/{userId}

这里面要有两个上下文根,一个是spring的,一个是camel的,具体配置参考如下:

########################################################
### 服务基本参数设置
########################################################
server:
    servlet:
        context-path: /idp

########################################################
### Camel配置
########################################################
camel:
  servlet:
    mapping:
      context-path: /api/*

那么最终的接口访问路径就是:

http(s)://{ip:port}/idp/api/v1/user/info/{userId}

接口参数

在学习中参考参考Spring MVC来针对性的看下Rest组件的多种使用方式,Spring MVC中@RequestParam、@RequestBody、@RequestHeader、@PathVariable。
处理的Request的不同内容部分分为四类:(主要讲解常用类型)
A、处理requet uri 部分(这里指uri template中variable,不含queryString部分)的注解: @PathVariable;
B、处理request header部分的注解: @RequestHeader, @CookieValue;
C、处理request body部分的注解:@RequestParam, @RequestBody;
D、处理attribute类型是注解: @SessionAttributes, @ModelAttribute;

  • @PathVariable

当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariable注解绑定它传过来的值到方法的参数上。
camel rest组件中 uriTemplate中定义的

rest:method:path[:uriTemplate]?[options]

# 例如 其中的sessionId userId
<from uri="rest:get:/v1/session/info:{sessionId}/{userId}"/>

# 对应的信息可以在header中读取
<transform>
     <simple>${header.sessionId} ${header.userId}</simple>
</transform>

配置后可以在组件中获取对应的参数信息:

<route id="helloRestApi">
<from uri="rest:get:helloRestApi:/{me}?queryParameters={msg}{age}"/>
<transform>
<simple>Camel组件-Rest组件,{header.msg},第2张{header.me}, age is Camel组件-Rest组件,{header.age}</simple> </transform> <log message=,第3张{body}"/>
</route>

  • @RequestParam

A) 常用来处理简单类型的绑定,通过 Request.getParameter() 获取的String可直接转换为简单类型的情况( String--> 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,所 以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值;
B)用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST;
C) 该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定;

rest:method:path[:uriTemplate]?[options]

# 例如 其中的sessionId userId
<from uri="rest:get:/v1/session/info?queryParameters={sessionId}{userId}"/>
  • @RequestBody

该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml。因为Spring MVC配置有FormHttpMessageConverter,所以也可以用来处理 application/x-www-form-urlencoded的内容,处理完的结果放在一个MultiValueMap<String, String>里。

body信息不需要额外定义,就可以直接使用, ${body}获取body内容

  • @RequestHeader

header信息不用单独定义,可以直接${header.xxxx}获取对应的变量值。

另外Camel Message Header中会存放一些其他额外的请求信息,比如请求方式,一般来说Camel消息体的Header内容相对来说比较少。额外更多信息需要自己定义Processor获取,比如想获取请求的源地址。


Camel组件-Rest组件,第4张
  • @ModelAttribute

该注解有两个用法,一个是用于方法上,一个是用于参数上;
用于方法上时:通常用来在处理@RequestMapping之前,为请求绑定需要从后台查询的model;用于参数上时:用来通过名称对应,把相应名称的值绑定到注解的参数bean上;要绑定的值来源于。
该情况在camle中可以用于请求的对象类型进行绑定

数据处理

使用内置组件处理

常见的内置组件包括simple、contant、header、property组件,可以对象属性进行基本的逻辑处理。

simple组件

Camel组件-Rest组件,第5张
simple组件
<route id="simple_body_detail">
    <from uri="rest:post:rest/simple/detail?queryParameters={message}"/>
    <process ref="remoteIpProcessor"></process>
    <!-- simple 获取json内容时 注意需要un marshal之后才能操作 ${body[name]} -->
    <unmarshal><json library="Jackson"></json></unmarshal>
    <setBody>
        <simple>
            {
                "code": 200,
                "data": {
                    "message": ${header.message},
                    "name": ${body[name]}
                },
                "remoteIp": ${exchangeProperty.RemoteAddress},
                "name": ${exchangeProperty.name},
                "body": ${body}
            }
        </simple>
    </setBody>
    <log message="${body}"/>
</route>

header语法

property语法

自定义process

routes定义了一系列的处理流程,prceoss是对每一步流程处理的具体逻辑实现。可以通过processor创建、修改processor的exchange对象,包括header、body、exchange property等属性信息。

import com.egoo.eeip.eeif.framework.base.util.server.IdGeneratorUtil;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;

/**
 * com.egoo.eeip.idp.server.process
 *
 * @author egoo
 * @date 2022/9/26
 */
public class DemoProcess implements Processor {
    @Override
    public void process(Exchange exchange) throws Exception {
        exchange.getIn().setHeader("seqNo", IdGeneratorUtil.nextId());
    }
}

在camel context中注册对应processor

<bean id="remoteIpProcessor" class="com.egoo.eeip.eeif.framework.idp.processor.servlet.ServletRemoteIpProcessor"></bean>

路由中定一个和使用对应的processor

<route>
  <processor ref="remoteIpProcessor"> </processor>
</route>

接口调用

报文组装

调用其他接口,就需要按照其他接口的接口格式进行数据包装,包括接口请求的方式method、请求头、请求体、请求的路径参数等进行组装。

示例程序如下:get请求 http://{{host}}/server/api/helloRestApi?msg=nihao&age=13 去调用post请求获取数据并返回结果
[图片上传失败...(image-54e7ab-1667102449354)]
代码配置如下:

<route id="helloRestApiCall">
  <from uri="rest:get:helloRestApiCall?queryString={msg}{age}"/>
  <setBody>
    <simple>{"msg": "${header.msg}", "age": ${header.age}}</simple>
  </setBody>
  <removeHeaders pattern="*"></removeHeaders>
  <setHeader name="CamelHttpMethod">
    <constant>POST</constant>
  </setHeader>
  <setHeader name="Content-Type">
    <constant>application/json;charset=UTF-8</constant>
  </setHeader>
  <log message="rest post ${body}"/>
  <to uri="rest:post:/idp/v1/demo/map?host=http://localhost:9888&amp;bridgeEndpoint=true"/>
</route>

本地post请求:

@RestController
@RequestMapping(value="/v1/demo", produces="application/json")
@Api(value="demo测试接口", description="demo测试接口")
@Slf4j
public class testController {

   @PostMapping("/map")
   @ResponseBody
   public Object post(@RequestBody Map map){
      System.out.println(map.toString());
      map.put("code",0);
      map.put("message","成功了");
      return map;
   }
}

结果处理

通常是对返回的报文进行重新整理满足不同业务前端的接口需求。结果处理通常使用jsonata组件来进行转换。

文件上传

通过MimeMultipart格式转换来处理,注意该组件依赖邮件组件,通过unmarshal将multipart格式转换成不带附件的普通格式,marshal转换程multipart格式。

<route>
  <from uri="rest:post:upload"></from>
  <unmarshal>
    <mimeMultipart></mimeMultipart>
  </unmarshal>
  <to uri="file:download?fileName=test.png"></to>
  <!-- 避免request header中默认的content type作为返回值返回 -->
  <setHeader name="Content-Type"><constant>application/json</constant></setHeader>
  <setBody>
    <simple>{"code": 200, "msg": "upload file success"}</simple>
  </setBody>
</route>

遗留问题:

  • 获取文件名称

一般在转换前要获取到文件名,用于保存的时候使用,mimeMultipart并未提供相关功能。参考自定义processor来处理。

<route id="multipart_file_processor">
    <from uri="rest:post:upload1"></from>
    <process ref="multipartFileProcessor"></process>
    <log message="${headers} ${body}"></log>
    <to uri="file:download/tmp?fileName=${header.CamelFileName}"></to>
    <setHeader name="Content-Type"><constant>application/json</constant></setHeader>
    <setBody>
        <simple>{"code": 200, "msg": "upload file success"}</simple>
    </setBody>
</route>
  • 一次上传多个文件

上传文件通过marshal格式化后,通过body读取相关内容,读取的内容需要根据boundary分割

<route>
  <from uri="rest:post:upload1/{path}"></from>
  <marshal>
    <mimeMultipart></mimeMultipart>
  </marshal>
  <log message="${body}"></log>
</route>
收到的body内容如下所示:每一个item内容Content-Dispositoin,由header中的Content-Type中的boundary进行分割。
Content-Type=multipart/form-data; boundary=--------------------------065816312379776045391551

[图片上传失败...(image-a87caf-1667102449354)]
针对报文编写内容解析来完成报文解析处理。详细参考eeif框架 MultipartFileProcessor。

  • 文件和其他参数同时用multipart方式,建议其他参数用路径参数或者query参数
<route>
  <from uri="rest:post:upload/{path}"></from>
  <unmarshal>
    <mimeMultipart></mimeMultipart>
  </unmarshal>
  <to uri="file:download?fileName=/${header.path}/test.png"></to>
  <setHeader name="Content-Type"><constant>application/json</constant></setHeader>
  <setBody>
    <simple>{"code": 200, "msg": "upload file success"}</simple>
  </setBody>
</route>

接口管理

通过rest-api和swagger ui管理rest api接口

参考资料

  • https://www.openapis.org/

https://www.xamrdz.com/backend/3wh1933990.html

相关文章: