25 Nisan 2022 Pazartesi

SpringMVC ResponseBodyAdvice Arayüzü - Response Nesnesi Değiştiren Interceptor

Giriş
Şu satırı dahil ederiz
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
Spring ile hazır gelen advice'lardan bir tanesi. Açıklaması şöyle
It helps us to modify the message i.e response object before it is written to the Response body.
supports metodu
İmzası şöyle
boolean supports(MethodParameter returnType,
                 Class<? extends HttpMessageConverter<?>> converterType)
Açıklaması şöyle
The MethodParameterargument helps us to check from which class and method the Request is coming and return the boolean value.  Based on it the BeforeBodyRead Method is Called.
beforeBodyWrite metodu
İmzası şöyle
T beforeBodyWrite(@Nullable T body,
                  MethodParameter returnType,
                  MediaType selectedContentType,
                  Class<? extends HttpMessageConverter<>> selectedConverterType,
                  ServerHttpRequest request,
                  ServerHttpResponse response)
Örnek
Şöyle yaparız
@RestControllerAdvice
public class DemoControllerAdvice implements 
  ResponseBodyAdvice<Map<String, String>> {

  @Override
  public boolean supports(
    MethodParameter returnType, 
    Class<? extends HttpMessageConverter<?>> converterType) {

    String className = returnType.getContainingClass().toString();
    String methodName = returnType.getMethod().toString();
    if (className.contains("DemoController_") && 
        methodName.contains("ResponseModification")) {
      return true;
    }
    return false;
  }

  @Override
  public Map<String, String> beforeBodyWrite(
    Map<String, String> body, 
    MethodParameter returnType,
    MediaType selectedContentType, 
    Class<? extends HttpMessageConverter<?>> selectedConverterType,
    ServerHttpRequest request, 
    ServerHttpResponse response) {

    body.put("body_data", "Age of the Person is 25 years");
    return body;
  }
}
Örnek
Şöyle yaparız. Burada @RestControllerAdvice yerine @ControllerAdvice kullanılıyor
@ControllerAdvice
public class ResponseBodyInterceptor implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { ... return body; } }

SpringMVC RequestBodyAdviceAdapter Sınıfı

Giriş
Spring ile hazır gelen advice'lardan bir tanesi

Örnek
Şöyle yaparız
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;

@ControllerAdvice
public class RequestBodyInterceptor extends RequestBodyAdviceAdapter {

  @Autowired
  HttpServletRequest request;

  @Override
  public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
    ...
    return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
  }

  @Override
  public boolean supports(MethodParameter methodParameter, Type targetType, 
    Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
  }
}

18 Nisan 2022 Pazartesi

SpringCloud Gateway GlobalFilter Arayüzü

Giriş
GlobalFilter ve GatewayFilter benziyorlar

Örnek
Şöyle yaparız
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

public class PostGlobalFilter implements GlobalFilter, Ordered {

  ...

  @Override
  public int getOrder() {
    return 0;
  }
}
Metodun içi şöyle
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  return chain.filter(exchange).then(Mono.fromRunnable(()->{
    ServerHttpResponse response = exchange.getResponse();
    HttpStatus responseStatus = response.getStatusCode();
    if(responseStatus.equals(HttpStatus.BAD_REQUEST)){
      String newResponseBody =
      "<body>\n" +
      "<h1 style=\"color:red;text-align:center\">Bad Request </h1>\n" +
      "<p>If you are seeing this page it means response body is modified.</p>\n" +
      "</body>";

      DataBuffer dataBuffer = response.bufferFactory()
        .wrap(newResponseBody.getBytes(StandardCharsets.UTF_8));
      response.getHeaders().setContentLength(newResponseBody.length());
      response.writeWith(Mono.just(dataBuffer)).subscribe();
      exchange.mutate().response(response).build();
    }
  }));
}


1 Nisan 2022 Cuma

Spring Profiles Kullanımı

Giriş
Açıklaması şöyle. Özellikle test kodlarında çok işe yarar.
Spring Boot provides profiles that help to create environment-specific configurations and stereotypes in the applications. 
Kullanılabilecek anotasyonlar şöyle

1. Spring boot 3.0.x ve Ötesi
Açıklaması şöyle
In spring boot 3.0.x onwards all the deprecated methods of 2.7.x have been removed. spring.profiles.include one of them that has been removed from spring boot. Instead of spring.profiles.include, spring boot has introduced spring.profiles.group in spring 2.4.x onwards. you have to make multiple groups based on profiles like spring.profiles.group.{env}={profile1},{profile2} in application.properties file.
Açıklaması şöyle
spring.profiles={env} is also removed, use spring.config.activate.on-profile={env}.
Örnek
Şöyle yaparız. Çalışılan ortam dev veya prod ise belirtilen profile dosyalar yüklenir
spring.profiles.group.dev=common
spring.profiles.group.prod=common
Yani ortam dev ise
application-common.properties
application-dev.properties
yüklenir

Örnek
Açıklaması şöyle
Profile Groups is another feature added in Boot 2.4. using this feature you can have multiple profiles activated under one group of profiles.

spring.profiles.group.development[0]=devdb 
spring.profiles.group.development[1]=devkafka

The application can now be started using --spring.profiles.active=development to active the development, devdb and devkafka profiles in one hit.
2. Spring boot 2.4.x - 2.7.x
Açıklaması şöyle. Yani eskisi gibi çalışabilmek mümkün
In spring boot 2.4.x spring.profiles.include marked as deprecated which will be removed in spring boot 3.0.0

To support the previous configuration, you can add the below line in application.properties.

spring.config.use-legacy-processing=true
3. Spring boot 2.3.x veya Öncesi
Active profile ismi verilir. Aktif profile isimleri birden fazla verilebilir ve virgül ile ayrılır. 4 yöntem var. 
1. Komut Satırı --spring.profiles.active kullanımı
2. Komut Satırı -D kullanımı
3. envrironment variables
4. application.properties dosyası

Örnek
Eğer active profile yanında ortak bir dosyayı daha yüklemek istersek spring.profiles.include kullanılır. Şöyle yaparız
spring.profiles.include=common
spring.profiles.active=dev
Böylece şu dosyalar yüklenebilir.
application-common.properties
application-dev.properties


1. Komut Satırı - --spring.profiles.active
--spring.profiles.active seçeneği kullanılır. 
Örnek
Şöyle yaparız.
start "Service 1" /B java.exe -jar service1.jar --spring.profiles.active=local
2. Komut satırı - java -Dspring.profiles.active
Aslında --spring.profiles.active ile -D--spring.profiles.active temelde aynı şeyler.
Örnek
Şöyle yaparız
java -jar -Dspring.profiles.active=dev application.jar
# or
java -jar application.jar --spring.profiles.active=dev
Örnek
Şöyle yaparız. Burada dev ve container isimli iki tane profile etkinleştiriliyor.
java -Dspring.profiles.active=dev,container -jar build/libs/dockeriser-0.0.1-SNAPSHOT.jar
3. environment variables
Örnek
Şöyle yaparız
export spring_profiles_active=dev
Örnek
environment variables koddan da verilebiliyor. Şöyle yaparız
@Autowired 
private ConfigurableEnvironment env; 
... 
env.setActiveProfiles("dev");

4. application.properties
Örnek
Profil vermek için şöyle yaparız.
spring.profiles.active=dev,local
Örnek - YAML Dosyası
Şöyle yaparız.
spring:
  profiles:
    active: dev
Açıklaması şöyle
If you prefer to have only one configuration (application.yml) file in your project, then you can separate each profile configuration using three dashes.

If you see in the above example, there are three sections, which are separated by three dashes. First section is for common properties which are enabled for all the spring profiles. Second section is for integration-test spring profile and third one is for prod profile.