resttemplate发送get、post请求(form、json)(功能封装)-编程思维

1.情景展示

一般情况下,如果要从服务器A去调服务器B,需要我们自己封装一个HttpUtils工具类。

发送GET或POST请求完成服务器对服务器的数据交互,使用RestTemplate组件就可以帮我们完成。

利用spring组件RestTemplate,如何用代码如何实现?

2.准备工作

<!--httpclient-->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
    <optional>true</optional>
</dependency>
<!--spring-web-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.18</version>
    <optional>true</optional>
</dependency>

说明:

通过 RestTemplate,我们可以非常方便的进行 Rest API 调用。

但是,在 Spring 5 中已经不再建议使用 RestTemplate,而是建议使用 WebClient。WebClient 是一个支持异步调用的 Client。

3.解决方案

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

GET请求封装

/**
 * 利用Spring组件发送GET请求
 * @description:
 * get请求调用sendGet()
 * post请求调用sendPost()
 * @author: Marydon
 * @date: 2023-05-26 9:21
 * @version: 1.0
 * @email: marydon20170307@163.com
 */
@Slf4j
public class SpringHttpUtils {
    /**
     * 发送get请求,拿到响应数据
     * @param url 请求地址
     * @param paramsMap 请求入参
     * @param responseDataClass 响应数据类型所对应的Class
     * @return T 响应数据
     * 数据类型与入参responseDataClass保持一致
     */
    public static <T> T sendGet(String url, Map<String, Object> paramsMap, Class<T> responseDataClass) {
        // 存放参数名与参数值
        List<NameValuePair> nameValuePairs = new ArrayList<>(paramsMap.size());
        // 遍历取出key和value并将其作为参数的name和value
        paramsMap.forEach((k, v) -> nameValuePairs.add(new BasicNameValuePair(k, v + "")));

        URI uri;
        try {
            // 形如:
            // http://www.cnblogs.com?Blog=%E5%8D%9A%E5%AE%A2%E5%9B%AD&Name=Marydon
            uri = new URIBuilder(url)
                    // 设置URL的字符集
                    .setCharset(StandardCharsets.UTF_8)
                    // 参数会被拼接到URL后面,中文会被自动编码
                    // url?param1=value1&param2=value2
                    .addParameters(nameValuePairs)
                    .build();

            log.info(uri.toString());
        } catch (URISyntaxException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }

        return getResponse(uri, responseDataClass);
    }

    /**
     * 调接口并完成响应数据的格式转换
     * @param uri
     * @param responseDataClass
     * 响应数据类型多对应的java类
     * @return 接口返回的数据
     */
    private static <T> T getResponse(URI uri, Class<T> responseDataClass) {
        if (null == uri) {
            throw new RuntimeException("请求地址URL为空!");
        }

        // 发送请求并获取响应结果
        String responseData = invokeGet(uri);

        // 响应数据类型
        T responseDataType;
        try {
            responseDataType = responseDataClass.newInstance();

            if (responseDataType instanceof JSONObject) {
                return (T) JSON.parseObject(responseData);
            } else if (responseDataType instanceof JSONArray) {
                return (T) JSON.parseArray(responseData);
            } else {
                return (T) responseData;
            }
        } catch (InstantiationException | IllegalAccessException e ) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 发送GET请求并获取响应结果
     * @param uri
     * 含:请求地址及请求参数
     * @return 响应结果
     * String
     */
    private static String invokeGet(URI uri) {
        //
        RestTemplate restTemplate = getRestTemplate();
        // 发送GET请求并拿到响应数据
        final ResponseEntity<String> getEntity = restTemplate.getForEntity(uri, String.class);
        // 响应数据
        String resultData =getEntity.getBody();
        log.info("接口地址:{}\n返回响应数据:\n{}", uri.toString(), resultData);

        return resultData;
    }

    /**
     * 创建Rest API 客户端
     * @explain
     * 其目的是:为了修改响应字符集
     * @return
     */
    private static RestTemplate getRestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        List<HttpMessageConverter<?>> httpMessageConverters = restTemplate.getMessageConverters();
        httpMessageConverters.forEach(httpMessageConverter -> {
            if(httpMessageConverter instanceof StringHttpMessageConverter){
                StringHttpMessageConverter messageConverter = (StringHttpMessageConverter) httpMessageConverter;
                // 将响应字符集改成UTF-8,默认是ISO-8859-1
                messageConverter.setDefaultCharset(StandardCharsets.UTF_8);
            }
        });
        return restTemplate;
    }

}

POST请求封装(FORM表单)

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.18</version>
    <optional>true</optional>
</dependency>
import org.springframework.http.HttpEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
 * 发送post请求,拿到响应数据
 * @description 提交form表单
 * @param url 请求地址
 * @param paramsMap 请求入参
 * @param responseDataClass 响应数据类型所对应的Class
 * @return T 响应数据
 * 数据类型与入参responseDataClass保持一致
 */
public static <T> T sendPostByForm(String url, Map<String, Object> paramsMap, Class<T> responseDataClass) {
    RestTemplate restTemplate = getRestTemplate();
    // 请求参数必须放到MultiValueMap当中
    MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>(paramsMap.size());
    paramMap.forEach(paramMap::add);
    // 必须将MultiValueMap放到HttpEntity当中
    HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap);

    final ResponseEntity<T> postEntity = restTemplate.postForEntity(url, httpEntity, responseDataClass);

    // 响应数据
    T body = postEntity.getBody();
    log.info("接口地址:{}\n返回响应数据:\n{}", url, body);

    return body;
}

POST请求封装(JSON)

/**
 * 发送post请求,拿到响应数据
 * @description JSON提交
 * @param url 请求地址
 * @param params 请求入参
 *               Map或JSON
 * @param responseDataClass 响应数据类型所对应的Class
 * @return T 响应数据
 * 数据类型与入参responseDataClass保持一致
 */
public static <T> T sendPostByJson(String url, Object params, Class<T> responseDataClass) {

    // JSONObject paramsJson;
    String paramsJsonStr;
    if (params instanceof JSONObject) {
        paramsJsonStr = params.toString();
    } else {
        // Map转JSON
        // paramsJson = MapUtils.toAliJson((Map<?, ?>) params);
        paramsJsonStr = JSON.toJSONString(params);
    }
    HttpHeaders headers = new HttpHeaders();
    // 相当于:application/json
    headers.setContentType(MediaType.APPLICATION_JSON);
    // 必须将MultiValueMap放到HttpEntity当中
    HttpEntity<String> httpEntity = new HttpEntity<>(paramsJsonStr, headers);

    RestTemplate restTemplate = getRestTemplate();
    final ResponseEntity<T> postEntity = restTemplate.postForEntity(url, httpEntity, responseDataClass);

    // 响应数据
    T body = postEntity.getBody();
    log.info("接口地址:{}\n返回响应数据:\n{}", url, body);

    return body;
}

4.调用

GET请求测试

public static void main(String[] args) {
    Map<String, Object> paramsMap = new HashMap<>(2);
    paramsMap.put("Name", "Marydon");
    paramsMap.put("Blog", "博客园");
    // 实际返回的是text/html
    sendGetRequest("http://www.cnblogs.com", paramsMap, String.class);
}

POST请求测试

form表单

sendPostByForm("http://www.cnblogs.com", paramsMap, String.class);

JSON

sendPostByJson("http://www.cnblogs.com", paramsMap, String.class);

 

写在最后

  哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

 相关推荐:

版权声明:本文版权归作者所有,遵循 CC 4.0 BY-SA 许可协议, 转载请注明原文链接
https://www.cnblogs.com/Marydon20170307/p/17435329.html

springboot 跳转到网页上的两种实现方式(转发与重定向详细对比)-编程思维

1.情景展示 虽然现在流行的是前后端分离,后端开发与前端往往只进行数据交互,不需要参与对网页跳转的控制及网页内容的开发。 但是,由服务器(后端)跳转到客户端(浏览器)或者从A服务器跳到B服务器是一项基本的能力。 在项目开发中,真正遇到的时候,该如何实现? 哪种实现方式更好? 2.具体分析 无论是springboot,S

springboot 自动装配的原理-编程思维

 自动装配原理 问题就是为什么我们直接导入依赖就可以使用了,甚至不用配置web.xml,tomcat等,springboot内部是如何实现的? 主启动类上的注解@SpringBootApplication里有三个重要注解: @SpringBootConfiguration@EnableAutoConfiguratio

springboot整合oss文件上传-编程思维

一、注册阿里云账号并开通OSS服务 1、登录阿里云账号 2、创建一个bucket 3、创建子用户 对自用户分配权限,打开操作OSS的全部权限(也可根据业务需求进行更改) 4、配置上传跨域规则 任何来源: * 允许方法: POST 任何请求头Headers: * 二、文件上传方式 1、服务器直传方式 每个O

springioc个人笔记-编程思维

上一章讲解了SpringBoot中的 AutoConfiguration自动装配,而这一章就来讲讲自动装配时会用到的Spring三大特性之一的IOC控制反转。 ​ 使用过Spring的人都熟知,SpringIOC容器可以在对象生成或初始化时就直接将数据注入到对象中,如果对象A的属性是另一个对象B,还可以将这个对象B的

根据域名获取对应的网络ip-编程思维

1.情景展示 以博客园为例,如何获取www.cnblogs.com对应的IP地址? 2.解决方案 博客园测试www.cnblogs.com 方式一:CMD命令 window+r → cmd 进入dos窗口 命令构成: nslookup 域名 输入命令:nslookup www.cnblogs.com并按回车键执行。

通用密钥,无需密码,在无密码元年实现passkeys通用密钥登录(基于django4.2/python3.10)-编程思维

毋庸讳言,密码是极其伟大的发明,但拜病毒和黑客所赐,一旦密码泄露,我们就得绞尽脑汁再想另外一个密码,但记忆力并不是一个靠谱的东西,一旦遗忘密码,也会造成严重的后果,2023年业界巨头Google已经率先支持了Passkeys登录方式,只须在设备上利用PIN码解锁、指纹或面部辨识等生物识别方式,即可验证身份,也就是说,可

【websocket】小白快速上手flask-socketio-编程思维

大家好,我是一个初级的Python开发工程师。本文是结合官方教程和代码案例,简单说下我对flask-socketio的使用理解。   一、websocket简介 websocket 说白一点就是,建立客户端和服务端双向通讯通道, 服务器可以主动向客户端发消息。   二、flask-socketio理解与使用 1. 环境