自定义HttpMessageConverter实现RestTemplate的exchange方法返回自定义格式数据

Posted houzheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义HttpMessageConverter实现RestTemplate的exchange方法返回自定义格式数据相关的知识,希望对你有一定的参考价值。

一 概述

 实现如下效果代码,且可正常获取到返回数据:

ResponseEntity<JsonObject> resEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, JsonObject.class,uriVariables);

 restTemplate的get和POST请求都有类型参数设置,所以可以直接返回转换成自定义的格式.比如:

restTemplate.getForObject("http://www.baiud.com",JsonObject.class);

但是exchange是无法指定返回类型的,只能使用spring默认提供的几种转换器转换的格式,定义其他格式会报错或者返回实体body为空

restTemplate的post方法支持设置header,但是get方法不支持,假如现在有个需求,使用get方法需要设置header权限,且返回我想要的格式,那么自定义HttpMessageConverter就派上用场了

也提现了spring非常强大的可扩展性

二 步骤

新建自定义转换类:

/**
 * 接口请求返回数据格式转换处理类,只处理String->JsonObject
 */
public class StringToJsonObjectMessageConverter extends AbstractHttpMessageConverter<JsonObject> {

    public StringToJsonObjectMessageConverter() {
        super(StandardCharsets.UTF_8,MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML); //设置支付类型
    }
    /**
     * HttpMessageConvert是否处理接受的这个类
     */
    @Override
    protected boolean supports(Class<?> aClass) {
        //isAssignableFrom: 判定此Class对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口
        return JsonObject.class==aClass;
    }

    //对数据进行处理并返回
    @Override
    protected JsonObject readInternal(Class<? extends JsonObject> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        //数据转换
        String temp = StreamUtils.copyToString(httpInputMessage.getBody(),Charset.forName("UTF-8"));
        return Tools.getGsonInstance().fromJson(temp, JsonObject.class);
    }

    //处理如何输出数据到response
    @Override
    protected void writeInternal(JsonObject jsonObject, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
        //可继续处理转换后的格式数据
        httpOutputMessage.getBody().write(jsonObject.getAsByte());
    }
}

配置修改自定义类顺序:

    @Bean
    public RestTemplate restTemplate() {
        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setConnectionRequestTimeout(30 * 1000);
        httpRequestFactory.setConnectTimeout(30 * 3000);
        httpRequestFactory.setReadTimeout(30 * 3000);
        RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
        // 支持返回JsonObject类型数据,需要在String之前,因为String支付所有的类型会直接解析
        restTemplate.getMessageConverters().set(1,new StringToJsonObjectMessageConverter());
        //spring转换默认编码是ISO_8859_1,如果乱码可修改支持中文编码
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
        return restTemplate;
    }

断点查看:

技术图片

三 原理

exchage方法源码点进去,看一下就知道了

        //获取HttpMessageConverter集合
        Iterator var8 = RestTemplate.this.getMessageConverters().iterator();
        //按照索引顺序进行迭代循环解析
        while(var8.hasNext()) {
            HttpMessageConverter<?> messageConverter = (HttpMessageConverter)var8.next();
            if (messageConverter instanceof GenericHttpMessageConverter) {
                GenericHttpMessageConverter<Object> genericConverter = (GenericHttpMessageConverter)messageConverter;
                if (genericConverter.canWrite((Type)requestBodyType, requestBodyClass, requestContentType)) {
                    if (!requestHeadersx.isEmpty()) {
                        requestHeadersx.forEach((key, values) -> {
                            httpHeadersx.put(key, new LinkedList(values));
                        });
                    }

                    if (RestTemplate.this.logger.isDebugEnabled()) {
                        if (requestContentType != null) {
                            RestTemplate.this.logger.debug("Writing [" + requestBody + "] as "" + requestContentType + "" using [" + messageConverter + "]");
                        } else {
                            RestTemplate.this.logger.debug("Writing [" + requestBody + "] using [" + messageConverter + "]");
                        }
                    }
                    //解析成功直接返回,不会走后面解析器
                    genericConverter.write(requestBody, (Type)requestBodyType, requestContentType, httpRequest);
                    return;
                }
            } else if (messageConverter.canWrite(requestBodyClass, requestContentType)) {
                if (!requestHeadersx.isEmpty()) {
                    requestHeadersx.forEach((key, values) -> {
                        httpHeadersx.put(key, new LinkedList(values));
                    });
                }

                if (RestTemplate.this.logger.isDebugEnabled()) {
                    if (requestContentType != null) {
                        RestTemplate.this.logger.debug("Writing [" + requestBody + "] as "" + requestContentType + "" using [" + messageConverter + "]");
                    } else {
                        RestTemplate.this.logger.debug("Writing [" + requestBody + "] using [" + messageConverter + "]");
                    }
                }

                messageConverter.write(requestBody, requestContentType, httpRequest);
                return;
            }
        }
        //如果都没有解析成功.抛异常
        String message = "Could not write request: no suitable HttpMessageConverter found for request type [" + requestBodyClass.getName() + "]";
        if (requestContentType != null) {
            message = message + " and content type [" + requestContentType + "]";
        }

        throw new RestClientException(message);

 

以上是关于自定义HttpMessageConverter实现RestTemplate的exchange方法返回自定义格式数据的主要内容,如果未能解决你的问题,请参考以下文章

SpringMVC处理Json-使用 HttpMessageConverter

Spring/Boot/Cloud系列知识:HttpMessageConverter转换器使用方式

Spring/Boot/Cloud系列知识:HttpMessageConverter转换器使用方式

Spring/Boot/Cloud系列知识:HttpMessageConverter转换器使用方式

Spring/Boot/Cloud系列知识:HttpMessageConverter转换器使用方式

无法写入请求:没有找到适合带有 Feign 的请求类型的 HttpMessageConverter