JAVA-11240 Moved spring-cloud to spring-cloud-modules
This commit is contained in:
+16
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.cloud.openfeign;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients
|
||||
public class ExampleApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ExampleApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.baeldung.cloud.openfeign.client;
|
||||
|
||||
import com.baeldung.cloud.openfeign.config.ClientConfiguration;
|
||||
import com.baeldung.cloud.openfeign.hystrix.JSONPlaceHolderFallback;
|
||||
import com.baeldung.cloud.openfeign.model.Post;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(value = "jplaceholder",
|
||||
url = "https://jsonplaceholder.typicode.com/",
|
||||
configuration = ClientConfiguration.class,
|
||||
fallback = JSONPlaceHolderFallback.class)
|
||||
public interface JSONPlaceHolderClient {
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/posts")
|
||||
List<Post> getPosts();
|
||||
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json")
|
||||
Post getPostById(@PathVariable("postId") Long postId);
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.cloud.openfeign.client;
|
||||
|
||||
import com.baeldung.cloud.openfeign.model.Payment;
|
||||
import com.baeldung.cloud.openfeign.oauthfeign.OAuthFeignConfig;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = "payment-client", url = "http://localhost:8081/resource-server-jwt", configuration = OAuthFeignConfig.class)
|
||||
public interface PaymentClient {
|
||||
|
||||
@RequestMapping(value = "/payments", method = RequestMethod.GET)
|
||||
List<Payment> getPayments();
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.cloud.openfeign.client;
|
||||
|
||||
import com.baeldung.cloud.openfeign.config.FeignConfig;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@FeignClient(name = "user-client", url="https://jsonplaceholder.typicode.com", configuration = FeignConfig.class)
|
||||
public interface UserClient {
|
||||
|
||||
@RequestMapping(value = "/users", method = RequestMethod.GET)
|
||||
String getUsers();
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.baeldung.cloud.openfeign.config;
|
||||
|
||||
import feign.Logger;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.auth.BasicAuthRequestInterceptor;
|
||||
import feign.codec.ErrorDecoder;
|
||||
import feign.okhttp.OkHttpClient;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class ClientConfiguration {
|
||||
|
||||
@Bean
|
||||
public Logger.Level feignLoggerLevel() {
|
||||
return Logger.Level.FULL;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ErrorDecoder errorDecoder() {
|
||||
return new ErrorDecoder.Default();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OkHttpClient client() {
|
||||
return new OkHttpClient();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RequestInterceptor requestInterceptor() {
|
||||
return requestTemplate -> {
|
||||
requestTemplate.header("user", "ajeje");
|
||||
requestTemplate.header("password", "brazof");
|
||||
requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
|
||||
};
|
||||
}
|
||||
|
||||
// @Bean - uncomment to use this interceptor and remove @Bean from the requestInterceptor()
|
||||
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
|
||||
return new BasicAuthRequestInterceptor("ajeje", "brazof");
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.cloud.openfeign.config;
|
||||
|
||||
import com.baeldung.cloud.openfeign.exception.BadRequestException;
|
||||
import com.baeldung.cloud.openfeign.exception.NotFoundException;
|
||||
import feign.Response;
|
||||
import feign.codec.ErrorDecoder;
|
||||
|
||||
public class CustomErrorDecoder implements ErrorDecoder {
|
||||
@Override
|
||||
public Exception decode(String methodKey, Response response) {
|
||||
|
||||
switch (response.status()){
|
||||
case 400:
|
||||
return new BadRequestException();
|
||||
case 404:
|
||||
return new NotFoundException();
|
||||
default:
|
||||
return new Exception("Generic error");
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.baeldung.cloud.openfeign.config;
|
||||
|
||||
import feign.Logger;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
public class FeignConfig {
|
||||
|
||||
@Bean
|
||||
Logger.Level feignLoggerLevel() {
|
||||
return Logger.Level.FULL;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.cloud.openfeign.controller;
|
||||
|
||||
import com.baeldung.cloud.openfeign.client.PaymentClient;
|
||||
import com.baeldung.cloud.openfeign.model.Payment;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
public class PaymentController {
|
||||
|
||||
private final PaymentClient paymentClient;
|
||||
|
||||
public PaymentController(PaymentClient paymentClient) {
|
||||
this.paymentClient = paymentClient;
|
||||
}
|
||||
|
||||
@GetMapping("/payments")
|
||||
public List<Payment> getPayments() {
|
||||
List<Payment> payments = paymentClient.getPayments();
|
||||
return payments;
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.cloud.openfeign.exception;
|
||||
|
||||
public class BadRequestException extends Exception {
|
||||
|
||||
public BadRequestException() {
|
||||
}
|
||||
|
||||
public BadRequestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public BadRequestException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BadRequestException: "+getMessage();
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.cloud.openfeign.exception;
|
||||
|
||||
public class NotFoundException extends Exception {
|
||||
|
||||
public NotFoundException() {
|
||||
}
|
||||
|
||||
public NotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public NotFoundException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NotFoundException: "+getMessage();
|
||||
}
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.baeldung.cloud.openfeign.fileupload.config;
|
||||
|
||||
public class ExceptionMessage {
|
||||
private String timestamp;
|
||||
private int status;
|
||||
private String error;
|
||||
private String message;
|
||||
private String path;
|
||||
|
||||
public String getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(String timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ExceptionMessage [timestamp=" + timestamp + ", status=" + status + ", error=" + error + ", message=" + message + ", path=" + path + "]";
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.baeldung.cloud.openfeign.fileupload.config;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.cloud.openfeign.support.SpringEncoder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import feign.codec.Encoder;
|
||||
import feign.codec.ErrorDecoder;
|
||||
import feign.form.spring.SpringFormEncoder;
|
||||
|
||||
public class FeignSupportConfig {
|
||||
@Bean
|
||||
public Encoder multipartFormEncoder() {
|
||||
return new SpringFormEncoder(new SpringEncoder(new ObjectFactory<HttpMessageConverters>() {
|
||||
@Override
|
||||
public HttpMessageConverters getObject() {
|
||||
return new HttpMessageConverters(new RestTemplate().getMessageConverters());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ErrorDecoder errorDecoder() {
|
||||
return new RetreiveMessageErrorDecoder();
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.baeldung.cloud.openfeign.fileupload.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.baeldung.cloud.openfeign.exception.BadRequestException;
|
||||
import com.baeldung.cloud.openfeign.exception.NotFoundException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import feign.Response;
|
||||
import feign.codec.ErrorDecoder;
|
||||
|
||||
public class RetreiveMessageErrorDecoder implements ErrorDecoder {
|
||||
private final ErrorDecoder errorDecoder = new Default();
|
||||
|
||||
@Override
|
||||
public Exception decode(String methodKey, Response response) {
|
||||
ExceptionMessage message = null;
|
||||
try (InputStream bodyIs = response.body()
|
||||
.asInputStream()) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
message = mapper.readValue(bodyIs, ExceptionMessage.class);
|
||||
} catch (IOException e) {
|
||||
return new Exception(e.getMessage());
|
||||
}
|
||||
switch (response.status()) {
|
||||
case 400:
|
||||
return new BadRequestException(message.getMessage() != null ? message.getMessage() : "Bad Request");
|
||||
case 404:
|
||||
return new NotFoundException(message.getMessage() != null ? message.getMessage() : "Not found");
|
||||
default:
|
||||
return errorDecoder.decode(methodKey, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.baeldung.cloud.openfeign.fileupload.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.baeldung.cloud.openfeign.fileupload.service.UploadService;
|
||||
|
||||
@RestController
|
||||
public class FileController {
|
||||
|
||||
@Autowired
|
||||
private UploadService service;
|
||||
|
||||
@PostMapping(value = "/upload")
|
||||
public String handleFileUpload(@RequestPart(value = "file") MultipartFile file) {
|
||||
return service.uploadFile(file);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/upload-mannual-client")
|
||||
public boolean handleFileUploadWithManualClient(
|
||||
@RequestPart(value = "file") MultipartFile file) {
|
||||
return service.uploadFileWithManualClient(file);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/upload-error")
|
||||
public String handleFileUploadError(@RequestPart(value = "file") MultipartFile file) {
|
||||
return service.uploadFile(file);
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.cloud.openfeign.fileupload.service;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.baeldung.cloud.openfeign.fileupload.config.FeignSupportConfig;
|
||||
|
||||
@FeignClient(name = "file", url = "http://localhost:8081", configuration = FeignSupportConfig.class)
|
||||
public interface UploadClient {
|
||||
@PostMapping(value = "/upload-file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
String fileUpload(@RequestPart(value = "file") MultipartFile file);
|
||||
|
||||
@PostMapping(value = "/upload-file-error", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
String fileUploadError(@RequestPart(value = "file") MultipartFile file);
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.cloud.openfeign.fileupload.service;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import feign.Headers;
|
||||
import feign.Param;
|
||||
import feign.RequestLine;
|
||||
import feign.Response;
|
||||
|
||||
public interface UploadResource {
|
||||
|
||||
@RequestLine("POST /upload-file")
|
||||
@Headers("Content-Type: multipart/form-data")
|
||||
Response uploadFile(@Param("file") MultipartFile file);
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.baeldung.cloud.openfeign.fileupload.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import feign.Feign;
|
||||
import feign.Response;
|
||||
import feign.form.spring.SpringFormEncoder;
|
||||
|
||||
@Service
|
||||
public class UploadService {
|
||||
private static final String HTTP_FILE_UPLOAD_URL = "http://localhost:8081";
|
||||
|
||||
@Autowired
|
||||
private UploadClient client;
|
||||
|
||||
public boolean uploadFileWithManualClient(MultipartFile file) {
|
||||
UploadResource fileUploadResource = Feign.builder().encoder(new SpringFormEncoder())
|
||||
.target(UploadResource.class, HTTP_FILE_UPLOAD_URL);
|
||||
Response response = fileUploadResource.uploadFile(file);
|
||||
return response.status() == 200;
|
||||
}
|
||||
|
||||
public String uploadFile(MultipartFile file) {
|
||||
return client.fileUpload(file);
|
||||
}
|
||||
|
||||
public String uploadFileError(MultipartFile file) {
|
||||
return client.fileUpload(file);
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.baeldung.cloud.openfeign.hystrix;
|
||||
|
||||
import com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient;
|
||||
import com.baeldung.cloud.openfeign.model.Post;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class JSONPlaceHolderFallback implements JSONPlaceHolderClient {
|
||||
|
||||
@Override
|
||||
public List<Post> getPosts() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Post getPostById(Long postId) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.baeldung.cloud.openfeign.model;
|
||||
|
||||
public class Payment {
|
||||
|
||||
private String id;
|
||||
private double amount;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public double getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(double amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.baeldung.cloud.openfeign.model;
|
||||
|
||||
public class Post {
|
||||
|
||||
private String userId;
|
||||
private Long id;
|
||||
private String title;
|
||||
private String body;
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.baeldung.cloud.openfeign.oauthfeign;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
@Configuration
|
||||
public class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf()
|
||||
.disable()
|
||||
.oauth2Client();
|
||||
http
|
||||
.authorizeRequests().anyRequest().permitAll();
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.baeldung.cloud.openfeign.oauthfeign;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
public class OAuthClientCredentialsFeignManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OAuthClientCredentialsFeignManager.class);
|
||||
|
||||
private final OAuth2AuthorizedClientManager manager;
|
||||
private final Authentication principal;
|
||||
private final ClientRegistration clientRegistration;
|
||||
|
||||
public OAuthClientCredentialsFeignManager(OAuth2AuthorizedClientManager manager, ClientRegistration clientRegistration) {
|
||||
this.manager = manager;
|
||||
this.clientRegistration = clientRegistration;
|
||||
this.principal = createPrincipal();
|
||||
}
|
||||
|
||||
private Authentication createPrincipal() {
|
||||
return new Authentication() {
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDetails() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return clientRegistration.getClientId();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
try {
|
||||
OAuth2AuthorizeRequest oAuth2AuthorizeRequest = OAuth2AuthorizeRequest
|
||||
.withClientRegistrationId(clientRegistration.getRegistrationId())
|
||||
.principal(principal)
|
||||
.build();
|
||||
OAuth2AuthorizedClient client = manager.authorize(oAuth2AuthorizeRequest);
|
||||
if (isNull(client)) {
|
||||
throw new IllegalStateException("client credentials flow on " + clientRegistration.getRegistrationId() + " failed, client is null");
|
||||
}
|
||||
return client.getAccessToken().getTokenValue();
|
||||
} catch (Exception exp) {
|
||||
logger.error("client credentials error " + exp.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.baeldung.cloud.openfeign.oauthfeign;
|
||||
|
||||
import feign.RequestInterceptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.oauth2.client.*;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
|
||||
@Configuration
|
||||
public class OAuthFeignConfig {
|
||||
|
||||
public static final String CLIENT_REGISTRATION_ID = "keycloak";
|
||||
|
||||
private final OAuth2AuthorizedClientService oAuth2AuthorizedClientService;
|
||||
private final ClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
public OAuthFeignConfig(OAuth2AuthorizedClientService oAuth2AuthorizedClientService,
|
||||
ClientRegistrationRepository clientRegistrationRepository) {
|
||||
this.oAuth2AuthorizedClientService = oAuth2AuthorizedClientService;
|
||||
this.clientRegistrationRepository = clientRegistrationRepository;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RequestInterceptor requestInterceptor() {
|
||||
ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(CLIENT_REGISTRATION_ID);
|
||||
OAuthClientCredentialsFeignManager clientCredentialsFeignManager =
|
||||
new OAuthClientCredentialsFeignManager(authorizedClientManager(), clientRegistration);
|
||||
return requestTemplate -> {
|
||||
requestTemplate.header("Authorization", "Bearer " + clientCredentialsFeignManager.getAccessToken());
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2AuthorizedClientManager authorizedClientManager() {
|
||||
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
|
||||
.clientCredentials()
|
||||
.build();
|
||||
|
||||
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
|
||||
new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, oAuth2AuthorizedClientService);
|
||||
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
|
||||
return authorizedClientManager;
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.baeldung.cloud.openfeign.service;
|
||||
|
||||
import com.baeldung.cloud.openfeign.model.Post;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface JSONPlaceHolderService {
|
||||
|
||||
List<Post> getPosts();
|
||||
|
||||
Post getPostById(Long id);
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.cloud.openfeign.service.impl;
|
||||
|
||||
import com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient;
|
||||
import com.baeldung.cloud.openfeign.model.Post;
|
||||
import com.baeldung.cloud.openfeign.service.JSONPlaceHolderService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class JSONPlaceHolderServiceImpl implements JSONPlaceHolderService {
|
||||
|
||||
@Autowired
|
||||
private JSONPlaceHolderClient jsonPlaceHolderClient;
|
||||
|
||||
@Override
|
||||
public List<Post> getPosts() {
|
||||
return jsonPlaceHolderClient.getPosts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Post getPostById(Long id) {
|
||||
return jsonPlaceHolderClient.getPostById(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
server.port=8085
|
||||
spring.main.allow-bean-definition-overriding=true
|
||||
spring.application.name= openfeign
|
||||
logging.level.com.baeldung.cloud.openfeign.client: DEBUG
|
||||
feign.hystrix.enabled=true
|
||||
|
||||
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=client_credentials
|
||||
spring.security.oauth2.client.registration.keycloak.client-id=payment-app
|
||||
spring.security.oauth2.client.registration.keycloak.client-secret=863e9de4-33d4-4471-b35e-f8d2434385bb
|
||||
spring.security.oauth2.client.provider.keycloak.token-uri=http://localhost:8083/auth/realms/master/protocol/openid-connect/token
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.baeldung.cloud.openfeign;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.baeldung.cloud.openfeign.fileupload.service.UploadService;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class OpenFeignFileUploadLiveTest {
|
||||
|
||||
@Autowired
|
||||
private UploadService uploadService;
|
||||
|
||||
private static String FILE_NAME = "fileupload.txt";
|
||||
|
||||
@Test
|
||||
public void whenFeignBuilder_thenFileUploadSuccess() throws IOException {
|
||||
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
|
||||
File file = new File(classloader.getResource(FILE_NAME).getFile());
|
||||
Assert.assertTrue(file.exists());
|
||||
FileInputStream input = new FileInputStream(file);
|
||||
MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain",
|
||||
IOUtils.toByteArray(input));
|
||||
Assert.assertTrue(uploadService.uploadFileWithManualClient(multipartFile));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAnnotatedFeignClient_thenFileUploadSuccess() throws IOException {
|
||||
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
|
||||
File file = new File(classloader.getResource(FILE_NAME).getFile());
|
||||
Assert.assertTrue(file.exists());
|
||||
FileInputStream input = new FileInputStream(file);
|
||||
MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain",
|
||||
IOUtils.toByteArray(input));
|
||||
String uploadFile = uploadService.uploadFile(multipartFile);
|
||||
Assert.assertNotNull(uploadFile);
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.baeldung.cloud.openfeign;
|
||||
|
||||
import com.baeldung.cloud.openfeign.model.Post;
|
||||
import com.baeldung.cloud.openfeign.service.JSONPlaceHolderService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class OpenFeignManualTest {
|
||||
|
||||
@Autowired
|
||||
private JSONPlaceHolderService jsonPlaceHolderService;
|
||||
|
||||
@Test
|
||||
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetPosts_thenListPostSizeGreaterThanZero() {
|
||||
|
||||
List<Post> posts = jsonPlaceHolderService.getPosts();
|
||||
|
||||
assertFalse(posts.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetPostWithId_thenPostExist() {
|
||||
|
||||
Post post = jsonPlaceHolderService.getPostById(1L);
|
||||
|
||||
assertNotNull(post);
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.baeldung.cloud.openfeign;
|
||||
|
||||
import com.baeldung.cloud.openfeign.client.PaymentClient;
|
||||
import com.baeldung.cloud.openfeign.model.Payment;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* This test can be used to verify OAuth2 Token functionality with Feign client
|
||||
* (https://www.baeldung.com/spring-cloud-feign-oauth-token).
|
||||
*
|
||||
* The following components should be setup and running, as described in the article, prior to running this test.
|
||||
*
|
||||
* Authorization Server - embedded Keycloak server with the correct client and client-secret defined in the master realm.
|
||||
* This will issue the auth tokens used by Feign client.
|
||||
* Further details are available at: https://www.baeldung.com/keycloak-embedded-in-spring-boot-app
|
||||
*
|
||||
* Resource Server - OAuth resource server requiring valid JWT token (issued by the Authorization Server).
|
||||
* Further details are available at: https://www.baeldung.com/spring-security-oauth-resource-server
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class OpenFeignOAuth2ManualTest {
|
||||
|
||||
@Autowired
|
||||
private PaymentClient paymentClient;
|
||||
|
||||
@Test
|
||||
public void whenGetPayment_thenListPayments() {
|
||||
|
||||
List<Payment> payments = paymentClient.getPayments();
|
||||
|
||||
assertFalse(payments.isEmpty());
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.cloud.openfeign;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = ExampleApplication.class)
|
||||
public class SpringContextTest {
|
||||
|
||||
@Test
|
||||
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user