调用第三方接口获取数据(简易版)

【2021-2-24补充】demo地址:https://github.com/ibfang/learning-examples.git

 

————-——————正文————————————

 

系统框架:springboot(与框架无关,仅作为记录)

实现流程:controller→service

举例:我现在打算调用京东万象的“笑话大全”api,通过这个接口调用数据,把笑话为我所用。

思路:

(1)写一个controller,用来接收用户从页面传过来的请求

(2)写一个service,用于实现业务需求,在这里也就是实现“怎么调用三方接口”这个需求

(1)(2)是实现手段,那实现“调用三方接口”这件事,我们还需要准备一样东西,那就是接口api。比如,我想要调用京东万象的“笑话大全”api,我们可以在京东万象上找到这个api接口,这是对方提供给你的。如下图:

其中,1是这个“笑话大全”的接口地址;2是你调用这个接口的请求方式,是get还是post;3是请求示例,也就是对方给你的一个调用的请求demo,你要按照他给你的示例去传参,你才能得到你想要的结果。请求参数我们可以看到,也有相对应的说明,比如page代表你这次请求的是第几页数据,因为对方可能有几十万条数据,不可能你一请求就把几十万条数据全部返给你,如果你每次请求都返几十万数据给你,这不现实,所以对方需要你给他一个页码,你想要第几页的数据,对方的数据就像一本书,你告诉他你要第几页的。然后maxResult是你要几条,比如一页里有100条数据,但是我只想要20条,于是你传一个maxResult=20给他(这里maxResult我没有截出来)。总之,请求示例是你要调用的接口给你的一个请求模板,你只要按照模板去请求就可以了。

当我们找到了我们所需要的api接口,我们就可以开始写代码了。我习惯先从controller说起,一层一层往下扒。

一  controller层

private String jokeApiKey = "40ff81dexxxxxxxxxxxx97a39d39";
    @Autowired
    ApiService apiService;
    /**
     * 京东万象-笑话api
     */
    @GetMapping("/getJoke")
    @ResponseBody
    public Output jokeApi() throws Exception {
        //得到long类型当前时间
        long l = System.currentTimeMillis();
        //new日期对象
        Date date = new Date(l);
        //转换提日期输出格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String time = dateFormat.format(date);

        String api = "https://way.jd.com/showapi/wbxh?time=" + time + "&page=1&maxResult=20&showapi_sign=bd0592992b4d4050bfc927fe7a4db9f3&appkey=" + jokeApiKey;

        String str = apiService.httpRequest(api);


        JSONObject jsonObject = JSON.parseObject(str);
        String code = jsonObject.getString("code");
        if (code == null) {
            throw new Exception("数据获取有误!");
        }
        JSONObject resultJsonObject = jsonObject.getJSONObject("result");
        JSONObject bodyJsonObject = resultJsonObject.getJSONObject("showapi_res_body");
        JSONArray contentListArray = bodyJsonObject.getJSONArray("contentlist");
        List<Item> itemList = JSONArray.parseArray(contentListArray.toJSONString(),Item.class);
        Output output = new Output();
        output.setResult(itemList);
        return output;
    }

 

二 service层

在controller层里我说了,我们暂时只需要关注1~4步。你在controller层里面拼接好了地址以后,就可以把拼接了你appKey、time等等参数的url传给service进行进一步的业务处理,也就是我们真正的调用三方接口的处理逻辑。

public String httpRequest(String apiPath) {
        BufferedReader in = null;
        StringBuffer result = null;
        //调用的api的接口地址
        String apiUrl = apiPath;
        try {
            URL url = new URL(apiPath);
            //打开和url之间的连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setRequestProperty("Charset", "utf-8");
            connection.connect();
            result = new StringBuffer();
            //读取URL的响应
            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            return result.toString(); //返回json字符串
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return null;
    }

上面这个方法可以直接copy拿去用。因为我也是一个技术渣,很多东西暂时只是会用。懂的还不是很多,所以不敢乱讲解。所以在这里就不讲解上面这个方法了。如果不懂,可以百度一下对应的语句代表什么功能。这个方法执行成功之后,返回的是一个json字符串。我们可以来看一下:

通过debug我们可以看到,result是一个字符串,它被返回回了service层。我们接着在service层里打断点,看service层是怎么做后续结果处理的。当然,怎么做取决于你自己,到此其实你已经拿到了数据了。后面对数据的处理完全取决于你的需求。

这里我们就来看一看的我处理方法吧。但首先我们要来看一下“笑话大全”api给的返回示例:

从上图中我们可以看出,我们所需要的数据就只是红色框框框出来的部分,其他数据对我们来说都是没用的。上图不规范,我们给它格式化一下,让它更规范:

从上图我们可以看出,我们要的数据被包了一层一层又一层。所以我们要是想拿到这个数据,就要一层一层的把“外衣”扒掉。

于是就用到了controller那张图中的第5步那些代码。我们debug看看

 

拿到了返回数据之后,你就可以把值一个一个取出来然后存到你的数据库里。当然你的数据库里一定要先有一张对应的表才是。

关于怎么取数据存数据。可以去看看我之前那篇博文。

 

不知道我有没有写明白啊。感觉写的越细越容易糊涂。

如果哪里有问题欢迎大家指正。我也是有大佬帮忙才写出来的,所以如果我哪里写的有问题欢迎大家指正,我们共同进步。

另外,在这里面,json包我用的是fastjson,它的maven依赖如下。别的特殊的包好像没有了。如果有你们可以提醒我,我后续补上。

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.57</version>
        </dependency>

最后的最后。

service层那个调用第三方接口的方法还有另一个:

public static JSONObject jsonPost(String urls, String text) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(urls);
        httpPost.setHeader("Content-Type", "application/json");
        httpPost.setEntity(new StringEntity(text));

        CloseableHttpResponse response = httpClient.execute(httpPost);
        HttpEntity entity = response.getEntity();
        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 JSON.parseObject(result);
    }

这个我在之前写的那篇博文里也写过。这里不详细写了。我只记录一下,方便自己后续回忆。

传参:

//对方要求以json格式把请求参数以post的方式传过去
JSONObject inner = new JSONObject();
inner.put("字段a", 字段a的值);
inner.put("字段b",字段b的值);
inner.put("字段c", 字段c的值);
//inner.put("pageindex", pageindex); // 这里忘记是什么参数了 你自己改回来了 已经全部ok了
inner.put("pageindex", pageindex);
// 这里参数是包装了两层的。不是.net不用包两层。看对方需求
JSONObject param = new JSONObject();
param.put("data", inner.toString());
String url = "http://xxxxxxxxd?transtime=" + time + "&token=".concat(token);
//返回JSON字符串
JSONObject rets = null;
rets = jsonPost(url, param.toString());

 

 

之前写的那篇调用三方接口的链接: https://blog.csdn.net/myme95/article/details/83106126

可以两篇结合一起看。东西都是一样的。只是之前那篇多了把数据取出来存到数据库中,而这一篇是直接返回给前端页面一个json

 

其他比较好的教程:https://www.jb51.net/article/84243.htm

java发送post请求,提交form表单的方法:https://www.cnblogs.com/bobc/p/8809761.html

别的教程:https://www.cnblogs.com/Marydon20170307/p/9202987.html

-------------------------

今天遇到一个小问题。我调用一个api,那个api的数据提交是form表单。而我之前包括这篇文章写的方法都是以json格式传参数的。所以就出现了问题,当我以json格式的参数去请求一个本应以表单形式提交参数的api,那边防火墙会拦截下来,告诉我参数不合法。

后来我知道了,post方法的参数请求有两种形式:form表单形式(key=value数据格式)和json形式(key:value数据形式)。这两种方式对应的调用方法大同小异。

 

注:代码里的Output只是一个自己封装的输出类而已。就像一个快递箱,我不管你往快递箱里面放什么东西,你就算不放东西,你让我抛出去我就抛出去。里面可以有“status”、“message”等字段,用于统一对外界回应。因为一个方法你总要返回一点东西给前端的,这样前端才知道他的接口有没有请求成功对吧。但是如果每个接口都有每个接口的返回内容,这样就显得很乱。于是就弄了一个统一的输出类Output。

输出类Output的代码(可以根据个人需求做个性化定制~,比如你可以多返回一个errorcode什么的,这都是Ok的):

import java.io.Serializable;

public class Output implements Serializable {

    //serialVersionUID 这个是序列化时要用到的,idea可以自动生成,
    //但是我也不知道怎么生成,可以自己百度一下。这是公司大佬之前
    //封装的(此处感恩大佬又让我学到了新东西!)
    private static final long serialVersionUID = 7247613666080613254L;

    //状态码,比如这里定义status默认200,代表接口调用成功。代表网络上的成功而已。
    private int status = 200; 

    //code有的人会写成errorCode,是“错误代码”的意思。这是代表业务逻辑上的成功与否‘
    //默认0,代表你的业务逻辑没问题,此次调用成功了。打个比方,你调用接口进行一个“新增”操作,
    //新增成功返回一个code=0代表你此次新增成功了。否则你返回一个code=201(或者其他随便什么
    //只要你喜欢)代表新增失败。
    private int code = 0;  

    //错误信息,比如“新增失败!”等
    private String message;

   //如果新增成功,就把你想要抛出去的东西放在result里面跑出去。result用Object定义。随便你
   //放什么进去都OK ,String、int、List...  whatever you want
    private Object result;

    public int getStatus() {
        return this.status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public int getCode() {
        return this.code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return this.message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getResult() {
        return this.result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    public Output() {
    }

    public Output(Object result) {
        this.result = result;
    }

    public Output(int code, String message) {
        this.code = code;
        this.message = message;
    }
}

 

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值