大家好,又见面了,我是你们的朋友全栈君。
前言:关于调用第三方接口获取数据,我在后面的日子中写过一篇简易版的带图的博文https://blog.csdn.net/myme95/article/details/89359677,建议先看这个简易版的。
本篇博文是我当时第一次做【调用第三方接口获取数据】时写的文章,当时主要还是当做学习笔记记录,方便自己日后回顾。而且这篇博文主要是围绕我自己当时在做的公司的一个项目,所以在步骤方面的解释也很省(毕竟是我自己做的项目,我自己知道流程,所以就没写很清楚,比如介绍哪一步是在干什么),再加上这里面涉及的一些实体都是我们公司自己封装的,例如那个输出类Output,所以从总体上来看这篇文章对于很多人来说可能读起来有点费劲。
简易版的博文,我是围绕一个京东开放接口写的,当时是在写一个自己的小项目,不涉及泄露商业代码之类的,所以从头到尾能写多详细就写多详细。但可能由于我写的太详细了,所以可能读起来更像一团乱麻???可总体来说我觉得比这篇应该更好接受吧。另外,如果大家看我那篇简易版的,可以去找到我当时作为案例的那个京东的接口,然后跟着我的步骤一步一步写,我觉得一路跟下来的话应该没什么问题吧?
【2021-2-24补充】demo地址(简易版):https://github.com/ibfang/learning-examples.git
——————————————正文————————————————
系统框架:springboot(和框架没有什么太大关系,仅记录一下)
调用路径:controller→service
第三方接口:http://xx.xxx.com:9905/api/list?transtime=20181017105600&token=abcdefghijklmn
请求参数:{“data”:”{\”xxx\”:\”\”,\”xx\”:\”\”,\”xxxx\”:\”\”,\”pageindex\”:1}”}
(注:因为有些公司的后台是用.net写的,所以java给它传数据要像上面那么传,即包两层,json里面套json,且有斜杠;如果不是.net的话,就不用这么封装,具体请求方法看对方的要求)
一 controller层
@ApiOperation("数据抓取")
@ApiImplicitParam(name = "ImportListInput",value = "输入参数",required = true,dataType = "ImportListInput")
@PostMapping("interface")
@ResponseBody
@PreAuthorize("isAuthenticated()")
public Output getQualityLevel(@Valid @RequestBody ImportListInput importListInput)throws Exception {
return mdmElianImportListService.getImportList(importListInput);
}
importListInput 为向第三方接口传送的请求参数,该接口的请求方式为POST,故,后面需要将我们输入的值转为json数据包传送
二 service层
public static final String ESB_ElIAN_XXX_EXCHANGE = "elian.xxx.exchange";//下面同步用到。我的需求里有同步。这和调用第三方接口无关。不用看
private static final Logger logger = LoggerFactory.getLogger(xxxService.class);
public Output getImportList(ImportListInput importListInput) throws IOException, YaolingException, ParseException {
//获取token (获取token也是调用第三方提供的接口获取的,方法与下面记录的类似,不作赘述)
String str = mdmElianGetTokenService.getToken();
JSONObject oj = new JSONObject(str.toString());
String errorcode = oj.get("errorcode").toString();
if (ObjectUtils.isEmpty(errorcode)) {
//单起一个线程 (当第三方的数据量过大时,需要起一个线程,以防止超时而造成的数据获取不全,应该有更好的优化方法,如线程
//池之类的,暂不会;线程的使用代码用粉色标出)
Thread ts = new Thread(new Runnable() {
@Override
public void run() {
JSONObject oj1 = new JSONObject(str.toString());
String data = oj1.get("data").toString();
JSONObject oj2 = new JSONObject(data.toString());
String token = oj2.get("token").toString();
int pageindex;
if ((Integer) mdmElianImportListInput.getPageindex() == null||mdmElianImportListInput.getPageindex() ==0) {
pageindex = 1;
} else {
pageindex = mdmElianImportListInput.getPageindex();
}
//得到long类型当前时间
long l = System.currentTimeMillis();
//new日期对象
Date date = new Date(l);
//转换提日期输出格式
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyyMMdd");
String time = dateFormat.format(date);//按要求生成请求url中的第一个参数transtime并与格式化为url示例中的样子
while (true) {
《--完整的请求示例从这里开始--》
//new一个JSONObject格式的参数inner将我们传入的参数转为json格式
JSONObject inner = new JSONObject();
//把我们传进来的参数分别赋值给inner中的各个参数,
//这些参数名要和请求包的参数名一致,毕竟这是传给对方的数据,如果和对方要求的
//参数名不一致,那么我们也拿不到数据
inner.put("xxx", importListInput.getDrugname());
inner.put("xx", importListInput.getCompanysceng());
inner.put("xxxx", importListInput.getEndTime());
inner.put("pageindex", pageindex);
// 这里参数是包装了两层的
//再new一个JSonObject类型的参数param,把上面的inner放到param中,实现两层包装,因为对方后台用的.net,所以包两层。具体包装几层,看接口要求,有的可能只一层就好了
JSONObject param = new JSONObject();
param.put("data", inner.toString());
//拼接请求的url,把url+transtime+token拼接在一起
String url = "http://xx.xxx.com:9905/api/importlist?transtime=" + time + "&token=".concat(token);
//定义一个JSONObject类型的rets用于接收返回的JSON数据
JSONObject rets = null;
try {
//调用第三方接口,并传参数给对方,jsonPost方法在最后面附上
rets = DataDownloadUtil.jsonPost(url, param.toString());
} catch (IOException e) {
e.printStackTrace();
}
//如果返回结果中errorcode为空,即请求成功(具体看对方怎么标识错误信息,有的可能不用errorcode,所以不可直接生搬硬套此代码)
String errorCode = (String) rets.get("errorcode")
if (ObjectUtils.isEmpty(errorCode)) {
//调用成功
JSONArray jsonArray = rets.getJSONArray("data");
//用一个集合接收返回的json数据中的data的值,遍历集合,取出数据
for (int i = 0, len = jsonArray.length(); i < len; i++) {
JSONObject jsonObject2 = (JSONObject) jsonArray.get(i);
//定义一个接受类importList,将接收的数据写进数据库
ImportList importList = new ImportList();
//jsonObject2.get("x_x").toString()中的“x_x”要和实际返回的json数据中的字段名一致,否则可能会出现找不到字段的错误提示
importList.setXx(jsonObject2.get("x_x").toString());
importList.setXxx(jsonObject2.get("x_xx").toString());
importList.setXxxx(jsonObject2.get("x_xxx").toString());
importList.setDrugnameeng(jsonObject2.get("drugnameeng").toString());
//如果存在时间类的数据,且自己的数据库中设计时将时间字段的类型设置为了datetime,那么在接收时要进行转换,将string型的数据转为date型的数据存入数据库
SimpleDateFormat sdfs = new SimpleDateFormat("yyyy-MM-dd");
try {
importList.setLisencecodedate(sdfs.parse(jsonObject2.get("date").toString()));
} catch (ParseException e) {
e.printStackTrace();
}
//保存此条数据,框架是springboot,所以有Repository。不要生搬硬套代码
importListRepository.save(importList);
// }
// 同步到xxxx平台,用不到就不用写了
rabbitTemplate.convertAndSend(CommonConstant.ESB_ElIAN_XXX_EXCHANGE,CommonConstant.UPDATE, importList);
}
} else {
try {
throw new YaolingException(errorCode);
} catch (YaolingException e) {
e.printStackTrace();
}
}
logger.debug("传过去的pageindex值:[{}]", pageindex); //控制台做监控,看是否数据正确翻页
//json数据中的null和一般的null不同,判断的时候要注意,不能用==null之类的
if (rets.isNull("nextpage")) {
logger.debug("返回的nextpage值为null,抓取结束");
break;
}
logger.debug("返回的nextpage值:[{}]", (Integer) rets.get("nextpage"));
//请求数据时,我们要告诉对方要第几页的数据,所以会传一个pageindex值过去,对方返回给我们数据时,会给我们一个nextpage值,如果这个值不为null或者“ ”就说明下一页还有数据,我们要把nextpage值赋值给pageindex继续传过去获取下一页的值,写进数据库,循环往复直至nextpage为null或者“”,这也就是上面为什么要用while循环的原因
pageindex = (Integer) rets.get("nextpage");
logger.debug("下一次要传的pageindex值:[{}]", pageindex);
//至此,一条数据的获取、存入结束
} //while
《--一个完整的请求及获取数据到写入数据库到此结束--》
}//线程
});//线程
ts.start(); //启动线程
} else {
throw new YaolingException(errorcode);
}
return new Output();
}
(请求的代码是用“《– –》《– –》”包起来的部分,上面获取token之后,蓝色之前的代码都是为了蓝色代码中的url中的token做服务的,所以不用太在意。)
jsonPost方法
protected JSONObject jsonPost(String urls, String text) throws IOException {
//创建一个HttpClient最新版的实现类CloseableHttpClient
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建post方法请求对象,并把拼接好的地址url赋值给它的请求参数urls
HttpPost httpPost = new HttpPost(urls);
//设置报文头为Content-Type。具体格式看实际需求,我只知道如果请求的数据包为raw时,用Content-Type
httpPost.setHeader("Content-Type", "application/json");
//设置参数到请求对象中
httpPost.setEntity(new StringEntity(text));
//执行请求操作,并拿到结果(同步阻塞)。(括号里的同步阻塞我也不知道什么意思,之后知道了再补上)
CloseableHttpResponse response = httpClient.execute(httpPost);
//获取结果实体
HttpEntity entity = response.getEntity();
//看返回状态是否正常,正常则把获取到的json字符串返回给调用者
int statue = response.getStatusLine().getStatusCode();
if (statue != HttpStatus.SC_OK) {
logger.error("http connect fail:{}", response.getStatusLine());
}
//返回结果
String result = EntityUtils.toString(entity, "utf-8");
return new JSONObject(result);
}
之前做了颜色标记的,不知道为什么发布以后就变成了一个个大黑块,都不知道重点在哪了,第一次做这种,凑合看吧。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/134017.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...