Spring RestTemplate远程调用过程
作者:盛世如恋
Spring RestTemplate远程调用
之前在一个服务中调用另一个服务的请求,可以使用UrlConnection类来拼接Http请求头,这个时候就会发现,很麻烦,使用SpringRestTemplate的话 进一步封装了拼接的代码,相对于来说较为便捷。
Spring RestTemplate封装了http请求,可以较为方便的在一个服务中调用另一个服务的请求。
说明: 下面的例子是 使用端口为 8075的服务 ,通过get/id来远程调用端口8086的服务的请求。
1、pom.xml加入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
2、调用服务中的SpringBoot启动类注入RestTemplate
@Bean public RestTemplate restTemplate(){ return new RestTemplate(); }
3、在需要使用的Controller类中自动导入RestTemplate
@Autowired RestTemplate restTemplate;
4、根据调用某服务的ip拼接 url
调用RestTemplate的api获取响应内容
@RequestMapping("get/{id}") public User getById(@PathVariable("id") Integer id ){ String url = "http://localhost:8086/get/"+id; User s = restTemplate.getForObject(url,User.class); return s; }
5、测试
调用成功
5、出现的问题和解决
如果使用RestTemplate的话,虽然为我们封装了http请求头等信息,但是url需要自己写,不够灵活。
1、如果调用的服务是一个集群呢,固定了ip地址是否不妥,解决方案是使用ribbon,保证多个服务集群用的服务名是一致的,拼接的url 的ip地址用服务名来拼接,这个时候就可以用一个url访问多个端口号不一样的相同服务了,ribbon会将服务名转换成可以用的端口号。但是调用的服务有多个,如何来选择一个服务请求呢?这个时候就需要一个负载均衡算法,常用的负载均衡的算法有 轮询等。
2、用于拼接的http还是感觉不够简便,还需要自己去拼接,可不可以更加灵活?可以使用feign来代替RestTemplate,feign是一个声明式的远程调用,集成了ribbon和hystrix。
RestTemplate远程调用时遇到的问题
最近公司给了个任务,让我跟第三方接口联调,正好项目使用的是SpringBoot那我自然而然想到了SpringMVC提供的RestTemplate 来进行远程调用,但是在使用RestTemplate远程调用时出现了点问题…
提示:以下是本篇文章正文内容,下面案例可供参考
1.引入代码
代码如下(示例):
ResponseEntity<String> responseEntity = restTemplate.postForEntity(activityParameterConfig.getPakageProvide() + "?sign=" + sign, jsonValue, String.class); String body = responseEntity.getBody(); System.out.println("body = " + body);
在将结果转化为String时成功获取到了结果:
body = {"status":100,"msg":"发送成功","info":{"telphonenum":"*******1272","list":[{"ticketnum":"94330075353","start_use_date":"2021-03-09","end_use_date":"2031-03-09"}],"serial":"fa6b0592741a4d838c6a4737323c0c34","serial_number":"202103091614452220"}}
但是直接转换为String还要再将其转换为DTO,所以索性就选择直接选择在RestTemplate封装结果时直接装换为对应DTO
2.引入代码
代码如下(示例):
ResponseEntity<GiftDistributeResDTO> entity = restTemplate.postForEntity(activityParameterConfig.getPakageProvide() + "?sign=" + sign, jsonValue, GiftDistributeResDTO.class); GiftDistributeResDTO distributeResDTO = entity.getBody(); System.out.println("distributeResDTO = " + distributeResDTO);
结果报错了…提示没有对应的HttpMessageConverter处理类型为Content Type [text/html;charset=utf-8]] 的数据。
2021-03-09 16:14:47.221 ERROR 13548 --- [nio-8082-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.example.demo.user.dto.GiftDistributeResDTO] and content type [text/html;charset=utf-8]] with root cause
org.springframework.web.client.UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.example.demo.user.dto.GiftDistributeResDTO] and content type [text/html;charset=utf-8]
小结
于是Debug了下发现RestTemplate中存在7种转换器:
其中将结果转换为我们要的DTO的是MappingJackson2HttpMessageConverter这个转换器,再进去看看这个转换器属性:
结果发现这个转换器所支持的MediaTypes不存在上述text/html这种类型,所以才会报错,既然找到了问题那就在创建RestTemplate时给它多加一些支持的类型:
@Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters(); for (HttpMessageConverter<?> httpMessageConverter : converters) { if(httpMessageConverter instanceof MappingJackson2HttpMessageConverter){ ArrayList<MediaType> mediaTypes = new ArrayList<>(); mediaTypes.add(MediaType.ALL); ((MappingJackson2HttpMessageConverter) httpMessageConverter).setSupportedMediaTypes(mediaTypes); } } return restTemplate; }
再次调试发现结果已经可以正常封装到我们需要的DTO了:
distributeResDTO = GiftDistributeResDTO(status=100, msg=发送礼包成功!, info=GiftDistributeInfo(telphonenum=*******1272, serial_number=202103091641391875, serial=27c66dbdce6a476481e895b852d82fd3, list=[GiftDistributeList(ticketnum=94330070661, start_use_date=2021-03-09, end_use_date=2031-03-09)]), url=null)
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。