一、Apache Camel作为规则路由和服务引擎的能力大家不知道的可百度了解下。然后可能读者会疑惑为啥要重新封装接口,多此一举,直调不就行了。其实有以下3个原因:
1.楼主负责的项目,公司程序对外的API接口入出参什么都是标准化固定了。比如固定的是json的入参格式,但是第三方提供的接口入参要求却是xml的格式。所以需要将对方的接口重新封装在发布新的接口地址给公司程序调用。这里就体现了Apache Camel 的规则路由能力了。
2.第三方提供的接口地址IP不在楼主项目部署服务器的安全体系下,需要做一些类似token或者网关认证之类的。
3.楼主公司程序是PB开发的,对方发布的接口是java的,而且需要获取鉴权令牌,有MD5的校验,如果不通过Apache Camel封装,开发人员需要将java的鉴权令牌校验用PB重写,为了节省开发资源,让开发省事点,所以用Apache Camel重新封装下。
二、实现上面重新封装发布目的,本例是做了两步的封装和发布,只需要两个组件。HTTP服务组件+groovy脚本即可。
鉴权令牌接口HTTP服务组件的配置如下。name一栏自定义名字即可。日志级别一栏有调试和错误两个级别,如果不想所有日志都打印,就设置为错误级别。method有post和get两个模式,本例是post。msgtype是入参格式,支持xml、json、txt等格式,本例是json。url一栏填写接口地址的后缀,可自定义,调用地址一栏显示的就是给到程序调用的接口地址。
鉴权令牌接口groovy脚本配置如下。把json的入参传入,组装成original ,定义createToken方法来创建新的token,这里用了cn.hutool.crypto.digest.Digester包和cn.hutool.crypto.digest.DigestAlgorithm包的一个MD5校验,然后加上时间戳timestamp,传入下一个路由。
package com.kingdeehit.cloud.integration.service;
import com.kingdeehit.cloud.core.exception.CloudBaseException;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import java.util.Map;
import cn.hutool.core.map.MapUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
public class Grovvy4 extends IGroovyPlugin {
private static final Digester MD5 = new Digester(DigestAlgorithm.MD5);
public static String createToken(String appId, String secret, long timestamp, String baseUrl, Map<String, String> params) //创建token的方法
{
String original = appId + secret + baseUrl + MapUtil.sortJoin(params, "&", "=", true) + timestamp;
// System.out.println(original);
return MD5.digestHex(original, StandardCharsets.UTF_8);
}
@Override
public void process(Exchange exchange) {
try {
Message message = exchange.getIn();
Map body = message.getBody(Map.class);
body = body.get("data");
String method=(String) body.get("method");
String appId = (String) body.get("appId");
String secret = (String) body.get("secret");
String baseUrl = "/jcjy/V1.0/api/sys/"+body.get("method");
String cardCode = (String) body.get("cardCode");
Map<String, String> params = new HashMap<>(2);
long timestamp = System.currentTimeMillis();
params.put("timestamp", String.valueOf(timestamp));
if (method=='existsReCureInfo'){
body.put("jyxm","")
};
body.remove("method");
for (String key : body.keySet()){
params.put(key,body.get(key))
};
String id = String.valueOf(timestamp);
body.put("timestamp", id);
//System.out.println(String.valueOf(timestamp));
String token = Grovvy4.createToken(appId, secret, timestamp, baseUrl, params);//根据入参创建token
//System.out.println("token:" + token);//可以吧token打印出来查看
body.put("token", token);
exchange.getIn().setBody(body);
message.setHeader("baseUrl",baseUrl);
message.setHeader("params",params);
} catch (Exception e) {
throw new CloudBaseException(e);
}
}
}
业务接口HTTP服务组件的配置如下。
业务接口调用的groovy脚本配置如下。把json的入参传入,转换成map,这里用了cn.hutool.http包的方法,包支持传入form(map)参数,用map格式请求接口,map相当于是json和xml的一个中转格式,注意把代码里的String url = "http://ip:port/jcjy/V1.0/api/sys/submitAccept" 这段换成自己项目里第三方的接口地址。
package com.kingdeehit.cloud.integration;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.kingdeehit.cloud.integration.service.IGroovyPlugin;
import com.kingdeehit.cloud.integration.utils.SpringUtils;
import org.apache.camel.Exchange;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.hutool.http.HttpRequest;
import org.apache.camel.Message;
import cn.hutool.http.HttpResponse;
import java.util.Map;
public class Groovy extends IGroovyPlugin {
@Override
public void process(Exchange exchange) {
Message message = exchange.getIn();//获取上一步HTTP服务端组件入参进来的json
Map map = (Map)message.getBody(); //新建一个map对象
map = map.get("data");//把获取的入参放到map对象里
String url = "http://ip:port/jcjy/V1.0/api/sys/submitAccept";//第三方发布的HTTP接口地址
HttpResponse execute = HttpRequest.post(url).header("Content-Type","application/x-www-form-urlencoded;charset=utf-8").form(map).execute();//使用HttpRequest方法推送入参到第三方接口地址
//form是传文件类型的,一般的字符传body
//message.setHeader("map",form(map));
String body = execute.body();//接口返回赋值给body
exchange.getIn().setBody(body);//把body输出到流里
}
}
整体的路由如下图。
三、入出参示例如下。
1.鉴权令牌HTTP接口入参用例
body: {
"data": {
"appId": "5fe8cf6adecbd68334789b3bac8bd0614e8452a76ad0c260d89bab8e4ca72afd5808b0ef3d595be4220e94dc9fffde7b24c41319740dd9e3001d5f7d7282a2d9",
"secret": "WsRPjsoNRQwbvrH88o1VKwN8TjnGQ4Q4",
"cardCode": "62************0428",
"jyxm": "9999",
"jcxm": "002101020150000-02001",
"method": "existsReCureInfo"
}
}
2.鉴权令牌HTTP接口的出参用例(这里的出参打印出的日志是map的格式,可以用一个转换组件,把map转成json格式)
body: {appId=5fe8cf6adecbd68334789b3bac8bd0614e8452a76ad0c260d89bab8e4ca72afd5808b0ef3d595be4220e94dc9fffde7b24c41319740dd9e3001d5f7d7282a2d9,
secret=WsRPjsoNRQwbvrH88o1VKwN8TjnGQ4Q4,
cardCode=62************0428,
jyxm=,
jcxm=002101020150000-02001,
timestamp=1713240136176,
token=8262251ce37416494fd38fd54e9fd2f7}
3.业务接口HTTP的入参示例(hrxx[n] 入参支持0..n多个排列)
body: {
"data": {
"appId": "328e6ade889ab9e38897ca01a9348fd39d64cdc2f452d094d21c1fe209c74624e60d0cef1ab999605598e1bc25c141213f5f8822f46ba49633a751e4dcf168ec",
"secret": "814X4qQgoCIqRRqZ2aWqG57Z26xRfOoR",
"token": "c87d4f83954a230e2cf9652a7658499f",
"timestamp": "1713235948156",
"cardCode": "62**************77",
"hrxx[0].type": "2",
"hrxx[0].jlHos": "62********10",
"hrxx[0].lsh": "15B414301749710EE0636764A8C06DC8",
"hrxx[0].isAccept": "2",
"hrxx[0].reason": "1",
"hrxx[0].others": "",
"hrxx[0].hrTime": "2024-04-16 10:50:39",
"hrxx[1].type": "2",
"hrxx[1].jlHos": "62********10",
"hrxx[1].lsh": "15B41430174F710EE0636764A8C06DC8",
"hrxx[1].isAccept": "2",
"hrxx[1].reason": "1",
"hrxx[1].others": "",
"hrxx[1].hrTime": "2024-04-16 10:50:39",
"hrxx[2].type": "2",
"hrxx[2].jlHos": "62********10",
"hrxx[2].lsh": "15B414301750710EE0636764A8C06DC8",
"hrxx[2].isAccept": "2",
"hrxx[2].reason": "1",
"hrxx[2].others": "",
"hrxx[2].hrTime": "2024-04-16 10:50:39"
}
}
4.业务接口HTTP的出参示例(groovy调http://ip:port/jcjy/V1.0/api/sys/submitAccept接口返回的出参)
body: {"code":"0","msg":"成功!","data":{"result":1}}