您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“如何解決Spring Cloud中使用Feign,@RequestBody無法繼承問題”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“如何解決Spring Cloud中使用Feign,@RequestBody無法繼承問題”吧!
Spring Cloud中使用Feign,@RequestBody無法繼承的問題
原因分析
解決方案
spring cloud 使用feign遇到的問題
1、示例
2、首次訪問超時(shí)問題
3、FeignClient接口中,如果使用到@PathVariable,必須指定其value
根據(jù)官網(wǎng)FeignClient的例子,編寫一個(gè)簡單的updateUser接口,定義如下
@RequestMapping("/user") public interface UserService { @RequestMapping(value = "/{userId}", method = RequestMethod.GET) UserDTO findUserById(@PathVariable("userId") Integer userId); @RequestMapping(value = "/update", method = RequestMethod.POST) boolean updateUser(@RequestBody UserDTO user); }
實(shí)現(xiàn)類
@Override public boolean updateUser(UserDTO user) { LOGGER.info("===updateUser, id = " + user.getId() + " ,name= " + user.getUsername()); return false; }
執(zhí)行單元測(cè)試,發(fā)現(xiàn)沒有獲取到預(yù)期的輸入?yún)?shù)
2018-09-07 15:35:38,558 [http-nio-8091-exec-5] INFO [com.springboot.user.controller.UserController] {} - ===updateUser, id = null ,name= null
SpringMVC中使用RequestResponseBodyMethodProcessor類進(jìn)行入?yún)?、出參的解析。以下方法根?jù)參數(shù)是否有@RequestBody注解判斷是否進(jìn)行消息體的轉(zhuǎn)換。
@Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); }
既然MVC使用RequestResponseBodyMethodProcessor進(jìn)行參數(shù)解析,可以實(shí)現(xiàn)一個(gè)定制化的Processor,修改supportParameter的判斷方法。
@Override public boolean supportsParameter(MethodParameter parameter) { //springcloud的接口入?yún)]有寫@RequestBody,并且是自定義類型對(duì)象 也按JSON解析 if (AnnotatedElementUtils.hasAnnotation(parameter.getContainingClass(), FeignClient.class) && isCustomizedType(parameter.getParameterType())) { return true; } return super.supportsParameter(parameter); }
此處的判斷邏輯可以根據(jù)實(shí)際框架進(jìn)行定義,目的是判斷到為Spring Cloud定義的接口,并且是自定義對(duì)象時(shí),使用@RequestBody相同的內(nèi)容轉(zhuǎn)換器。
實(shí)現(xiàn)定制化的Processor后,還需要讓自定義的配置生效,有兩種方案可選:
直接替換RequestResponseBodyMethodProcessor,在SpringBoot下需要自定義RequestMappingHandlerAdapter。
實(shí)現(xiàn)WebMvcConfigurer中的addArgumentResolvers接口
這里采用較為簡單的第二種方式,初始化時(shí)的消息轉(zhuǎn)換器根據(jù)需要進(jìn)行加載:
public class XXXWebMvcConfig implements WebMvcConfigurer { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); stringHttpMessageConverter.setWriteAcceptCharset(false); List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(5); messageConverters.add(new ByteArrayHttpMessageConverter()); messageConverters.add(stringHttpMessageConverter); messageConverters.add(new SourceHttpMessageConverter<>()); messageConverters.add(new AllEncompassingFormHttpMessageConverter()); CustomizedMappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new CustomizedMappingJackson2HttpMessageConverter(); jackson2HttpMessageConverter.setObjectMapper(defaultObjectMapper()); messageConverters.add(jackson2HttpMessageConverter); ViomiMvcRequestResponseBodyMethodProcessor resolver = new ViomiMvcRequestResponseBodyMethodProcessor(messageConverters); resolvers.add(resolver); }
修改完成后,微服務(wù)的實(shí)現(xiàn)類即可去掉@RequestBody注解。
spring cloud 使用feign 項(xiàng)目的搭建 在這里就不寫了,本文主要講解在使用過程中遇到的問題以及解決辦法
@RequestMapping(value = "/generate/password", method = RequestMethod.POST) KeyResponse generatePassword(@RequestBody String passwordSeed);
在這里 只能使用 @RequestMapping(value = "/generate/password", method = RequestMethod.POST) 注解 不能使用
@PostMapping 否則項(xiàng)目啟動(dòng)會(huì)報(bào)
Caused by: java.lang.IllegalStateException: Method generatePassword not annotated with HTTP method type (ex. GET, POST) 異常
原因:Hystrix默認(rèn)的超時(shí)時(shí)間是1秒,如果超過這個(gè)時(shí)間尚未響應(yīng),將會(huì)進(jìn)入fallback代碼。
而首次請(qǐng)求往往會(huì)比較慢(因?yàn)镾pring的懶加載機(jī)制,要實(shí)例化一些類),這個(gè)響應(yīng)時(shí)間可能就大于1秒了。
解決方法:
<1:配置Hystrix的超時(shí)時(shí)間改為5秒
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
<2:禁用Hystrix的超時(shí)時(shí)間
hystrix.command.default.execution.timeout.enabled: false
<3:禁用feign的hystrix 功能
feign.hystrix.enabled: false
注:個(gè)人推薦 第一 或者第二種 方法
spring cloud feign 使用 Apache HttpClient
問題:1 沒有指定 Content-Type 是情況下 會(huì)出現(xiàn)如下異常 ? 這里很納悶?
Caused by: java.lang.IllegalArgumentException: MIME type may not contain reserved characters
在這里有興趣的朋友可以去研究下源碼
ApacheHttpClient.class private ContentType getContentType(Request request) { ContentType contentType = ContentType.DEFAULT_TEXT; for (Map.Entry<String, Collection<String>> entry : request.headers().entrySet()) // 這里會(huì)判斷 如果沒有指定 Content-Type 屬性 就使用上面默認(rèn)的 text/plain; charset=ISO-8859-1 // 問題出在默認(rèn)的 contentType : 格式 text/plain; charset=ISO-8859-1 // 轉(zhuǎn)到 ContentType.create(entry.getValue().iterator().next(), request.charset()); 方法中看 if (entry.getKey().equalsIgnoreCase("Content-Type")) { Collection values = entry.getValue(); if (values != null && !values.isEmpty()) { contentType = ContentType.create(entry.getValue().iterator().next(), request.charset()); break; } } return contentType; }
ContentType.class public static ContentType create(final String mimeType, final Charset charset) { final String normalizedMimeType = Args.notBlank(mimeType, "MIME type").toLowerCase(Locale.ROOT); // 問題在這 check 中 valid f方法中 Args.check(valid(normalizedMimeType), "MIME type may not contain reserved characters"); return new ContentType(normalizedMimeType, charset); } private static boolean valid(final String s) { for (int i = 0; i < s.length(); i++) { final char ch = s.charAt(i); // 這里 在上面 text/plain;charset=UTF-8 中出現(xiàn)了 分號(hào) 導(dǎo)致檢驗(yàn)沒有通過 if (ch == '"' || ch == ',' || ch == ';') { return false; } } return true; }
解決辦法 :
@RequestMapping(value = "/generate/password", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
注解中指定: Content-Type 即 指定 consumes 的屬性值 : 這里 consumes 屬性的值在這不做具體講解,有興趣的可以去研究下
到此,相信大家對(duì)“如何解決Spring Cloud中使用Feign,@RequestBody無法繼承問題”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。