Использование @RequestLine с Feign
У меня есть рабочий интерфейс Feign, определенный как:
@FeignClient("content-link-service")
public interface ContentLinkServiceClient {
@RequestMapping(method = RequestMethod.GET, value = "/{trackid}/links")
List<Link> getLinksForTrack(@PathVariable("trackid") Long trackId);
}
Если я изменю это, чтобы использовать @RequestLine
@FeignClient("content-link-service")
public interface ContentLinkServiceClient {
@RequestLine("GET /{trackid}/links")
List<Link> getLinksForTrack(@Param("trackid") Long trackId);
}
Я получаю исключение
Вызывается: java.lang.IllegalStateException: метод getLinksForTrack не аннотирован типом метода HTTP (например, GET, POST)
Есть идеи почему?
4 ответа
Я не ожидал бы, что это сработает.
@RequestLine
является основной аннотацией Feign, но вы используете Spring Cloud @FeignClient
который использует аннотации Spring MVC.
Весна создала свой собственный Feign Contract
чтобы позволить вам использовать Spring's @RequestMapping
аннотации вместо Feigns. Вы можете отключить это поведение, включив бин типа feign.Contract.Default
в контексте вашего приложения.
Если вы используете spring-boot
(или что-нибудь, использующее конфигурацию Java), включая это в @Configuration
класс должен снова включить аннотации Feign:
@Bean
public Contract useFeignAnnotations() {
return new Contract.Default();
}
Причина, по которой я получил эту ошибку, заключается в том, что я использовал оба@FeignClient
и@RequestLine
аннотации в моемFooClient
интерфейс.
Перед исправлением.
import org.springframework.cloud.openfeign.FeignClient; // @FeignClient
import feign.RequestLine; // @RequestLine
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient("foo")
public interface FooClient {
@RequestLine("GET /api/v1/foos/{fooId}")
@Headers("Content-Type: application/json")
ResponseEntity getFooById(@PathVariable("fooId") Long fooId); // I mistakenly used @PathVariable annotation here, but this should be @Param
}
Затем я получил эту ошибку.
Caused by: java.lang.IllegalStateException: Method FooClient#getFooById(Long) not annotated with HTTP method type (ex. GET, POST)
После исправления
// removed @FeignClient
// removed @PathVariable
import feign.Param; // Added
import feign.RequestLine; // @RequestLine
// removed @FeignClient("foo")
public interface FooClient {
@RequestLine("GET /api/v1/foos/{fooId}")
@Headers("Content-Type: application/json")
Foo getFooById(@Param("fooId") Long fooId); // used @Param
}
Если вас интересуют классы конфигурации.
- Обратите внимание, что я пытался создать Feign Clients вручную.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScans(value = {
@ComponentScan(basePackages = {
"com.example.app.service.web.client",
})
})
public class FeignConfig {
@Value(value = "${app.foo.service.client.url}")
protected String url; // http://localhost:8081/app
@Bean
public FooClient fooClient() {
FooClient fooClient = Feign.builder()
// .client(RibbonClient.create())
.client(new OkHttpClient())
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.logger(new Slf4jLogger(FooClient.class))
.logLevel(Logger.Level.FULL)
.target(FooClient.class, url);
return fooClient;
}
}
Рекомендации
Твой
@RequestMapping
значение выглядит нормально, но вам, вероятно, стоит подумать о его небольшом переписывании:
@GetMapping(value = "/{trackid}/links")
List<Link> getLinksForTrack(@PathVariable(name = "trackid") Long trackId);
Между прочим, мне не удалось получить
@RequestLine
работать из-за той же ошибки, что и ваша.
Также для
@ReactiveFeignClients
Contract.Default()
приводит к следующим ошибкам:
java.lang.IllegalStateException: Method MyClient#doStuff(String,String) not annotated with HTTP method type (ex. GET, POST)
Warnings:
- Class MyClient has annotations [Component, ReactiveFeignClient, Metadata] that are not used by contract Default
- Method doStuff has an annotation GetMapping that is not used by contract Default
и должен быть исправлен следующим образом:
var MyClient = WebReactiveFeign.builder()
.contract(new ReactiveContract(new SpringMvcContract()))
.target(MyClient, "http://example.com")