项目场景:

使用RestTemplate来访问第三方https接口,接口类型为POST,返回数据为JSON,需要忽略https证书,因此对RestTemplate 进行配置,通过HttpClient的请求工厂(HttpComponentsClientHttpRequestFactory)进行构建。HttpComponentsClientHttpRequestFactory使用一个信任所有站点的HttpClient就可以解决问题了。


问题描述

中间踩坑:
报错内容:

no suitable HttpMessageConverter found for response type [class cn.smxy.testSpring.vo.TokenVO] and content type [application/octet-stream]

没有为响应类型 [class cn.smxy.testSpring.vo.TokenVO] 和内容类型 [applicationoctet-stream] 找到合适的 HttpMessageConverter


解决方案:

全局配置中加上
mediaTypes.add(MediaType.APPLICATION_JSON);
mediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);

package cn.smxy.testSpring.config;

import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.util.ArrayList;
import java.util.List;

public class HttpMessageConverter extends MappingJackson2HttpMessageConverter {
    public HttpMessageConverter(){
        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.TEXT_PLAIN);
        mediaTypes.add(MediaType.TEXT_HTML);
        mediaTypes.add(MediaType.APPLICATION_JSON);
        mediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
        setSupportedMediaTypes(mediaTypes);
    }
}

完整代码:

配置pom.xml

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
</dependency>

1.创建一个SSL类代码如下

跳过证书验证,信任所有站点的HttpClient

package cn.smxy.testSpring.util;

import org.springframework.http.client.SimpleClientHttpRequestFactory;

import javax.net.ssl.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

/**
 * @author nzh
 * @date 2022/8/22 16:45
 */
public class SSL extends SimpleClientHttpRequestFactory {
    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        if (connection instanceof HttpsURLConnection) {
            prepareHttpsConnection((HttpsURLConnection) connection);
        }
        super.prepareConnection(connection, httpMethod);
    }

    private void prepareHttpsConnection(HttpsURLConnection connection) {
        connection.setHostnameVerifier(new SkipHostnameVerifier());
        try {
            connection.setSSLSocketFactory(createSslSocketFactory());
        } catch (Exception ex) {
            // Ignore
        }
    }

    private SSLSocketFactory createSslSocketFactory() throws Exception {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, new TrustManager[] { new SkipX509TrustManager() }, new SecureRandom());
        return context.getSocketFactory();
    }

    private class SkipHostnameVerifier implements HostnameVerifier {

        @Override
        public boolean verify(String s, SSLSession sslSession) {
            return true;
        }

    }

    private static class SkipX509TrustManager implements X509TrustManager {

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

    }
}

2.自定义HttpMessageConverter类,继承MappingJackson2HttpMessageConverter 消息转换器

package cn.smxy.testSpring.config;

import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.util.ArrayList;
import java.util.List;

public class HttpMessageConverter extends MappingJackson2HttpMessageConverter {
    public HttpMessageConverter(){
        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.TEXT_PLAIN);
        mediaTypes.add(MediaType.TEXT_HTML);
        mediaTypes.add(MediaType.APPLICATION_JSON);
        mediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
        setSupportedMediaTypes(mediaTypes);
    }
}

3.创建一个RestTemplateConfig类代码如下:


package cn.smxy.testSpring.config;

import cn.smxy.testSpring.util.SSL;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
 
/**   
 * @ClassName:  RestTemplateConfig   
 * @Description:  RestTemplate配置类
 * @author: nzh
 */
@Configuration
public class RestTemplateConfig {
 
	@Bean
	public RestTemplate restTemplate( ClientHttpRequestFactory factory) {
		RestTemplate restTemplate = new RestTemplate(factory);
		// 支持中文编码
		restTemplate.getMessageConverters().add(new HttpMessageConverter());
		return restTemplate;
	}
 
	@Bean
	public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
		SSL factory = new SSL(); //这里使用刚刚配置的SSL
		// SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
		factory.setReadTimeout(5000);//单位为ms
		factory.setConnectTimeout(5000);//单位为ms
		return factory;
	}
}
 

4.调用代码,单元测试 MultiValueMap,LinkedMultiValueMap别改 否则参数会传输失败


@SpringBootTest(classes = TestSpringApplication.class)
@RunWith(SpringRunner.class)

public class SpringApplicationTests {

    @Test
    public void contextLoads() {
        // 请求头信息
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.valueOf("application/x-www-form-urlencoded"));
        //设置为表单提交,按需求加
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        // 组装请求信息
        MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>();
        //  也支持中文
        params.add("userName", "你的用户名");
        params.add("password", "你的密码");
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(params, headers);
        //VO是接口返回类
        TokenVO tokenVO = restTemplate.postForObject("你的接口地址", requestEntity, TokenVO.class);
        System.out.println(tokenVO);
    }
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐