Spring Boot Http İstek Durdurucuları Ekleme


108

Spring boot uygulamasına HttpRequest durdurucu eklemenin doğru yolu nedir? Yapmak istediğim, her http isteği için günlük istekleri ve yanıtlarıdır.

Spring boot belgeleri bu konuyu hiç kapsamaz. ( http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/ )

Spring'in eski sürümleriyle aynı şeyin nasıl yapılacağına dair bazı web örnekleri buldum, ancak bunlar applicationcontext.xml ile çalışıyor. Lütfen yardım et.


Merhaba @ riship89 ... HandlerInterceptorBaşarıyla uyguladım . İyi çalışıyor. Tek sorun bazı vardır internal HandlerInterceptoro tarafından ele edilmeden önce bir istisna atar custom HandlerInterceptor. afterCompletion()Hata HandlerInterceptor iç uygulaması tarafından atılan sonra geçersiz sayılmıştır yöntemi denir. Bunun için bir çözümünüz var mı?
Chetan Oswal

Yanıtlar:


157

Spring Boot'u kullandığınız için, mümkün olduğunda Spring'in otomatik yapılandırmasına güvenmeyi tercih edeceğinizi varsayıyorum. Önleyicileriniz gibi ek özel konfigürasyon eklemek için, sadece bir konfigürasyon veya bean değeri sağlayın WebMvcConfigurerAdapter.

İşte bir yapılandırma sınıfı örneği:

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

  @Autowired 
  HandlerInterceptor yourInjectedInterceptor;

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(...)
    ...
    registry.addInterceptor(getYourInterceptor()); 
    registry.addInterceptor(yourInjectedInterceptor);
    // next two should be avoid -- tightly coupled and not very testable
    registry.addInterceptor(new YourInterceptor());
    registry.addInterceptor(new HandlerInterceptor() {
        ...
    });
  }
}

NOT mvc için Spring Boots otomatik yapılandırmasını korumak istiyorsanız, bunu @EnableWebMvc ile açıklamayın .


Güzel! İyi görünüyor! Registry.addInterceptor (...) içinde neler olduğuna dair herhangi bir örnek? "..." örneğini merak ediyorum
riship89

6
Enjekte Edilen Algılayıcınızda @Component ek açıklamasını kullanın
Paolo


4
Hata alıyorum The type WebMvcConfigurerAdapter is deprecated. Spring Web MVC 5.0.6 kullanıyorum
John Henckel

8
İlkbahar 5'te, WebMvcConfigurerAdapter'ı genişletmek yerine WebMvcConfigurer'ı uygulayın. Java 8 arabirimleri varsayılan uygulamalara izin verdiğinden, artık bağdaştırıcının kullanılması gerekmez (bu nedenle kullanımdan kaldırılmıştır).
edgraaff

89

WebMvcConfigurerAdapterİlkbahar 5 ile kullanımdan kaldırılacak. Javadoc'tan :

5.0 itibarıyla @deprecated {@link WebMvcConfigurer} varsayılan yöntemlere sahiptir (Java 8 baseline ile mümkün kılınmıştır) ve bu adaptöre ihtiyaç duyulmadan doğrudan uygulanabilir

Yukarıda belirtildiği gibi yapmanız gereken, yöntemi uygulamak WebMvcConfigurerve geçersiz kılmaktır addInterceptors.

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyCustomInterceptor());
    }
}

10
Cevabınız eksik çünküMyCustomInterceptor
peterchaula

33

Yaylı önyükleme uygulamasına önleyici eklemek için aşağıdakileri yapın

  1. Bir interceptor sınıfı oluşturun

    public class MyCustomInterceptor implements HandlerInterceptor{
    
        //unimplemented methods comes here. Define the following method so that it     
        //will handle the request before it is passed to the controller.
    
        @Override
        public boolean preHandle(HttpServletRequest request,HttpServletResponse  response){
        //your custom logic here.
            return true;
        }
    }
  2. Bir konfigürasyon sınıfı tanımlayın

    @Configuration
    public class MyConfig extends WebMvcConfigurerAdapter{
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(new MyCustomInterceptor()).addPathPatterns("/**");
        }
    }
  3. Bu kadar. Artık tüm istekleriniz MyCustomInterceptor'ın preHandle () yöntemi altında tanımlanan mantıktan geçecektir.


1
Bazı genel doğrulamaları yapmak için başvuruma gelen kayıt isteklerini engellemek için bu yolu izledim. Ama sorun şu ki, getReader() has already been called for this requesthatayı alıyorum. Gerçek talebin bir kopyasını kullanmadan bunu aşmanın daha basit bir yolu var mı?
47'de vigamage

Ön işleyici çağrıldığında, istek gövdesi mevcut değil, yalnızca parametreler, İstek gövdesinde doğrulama yapmak için tercih edilen yol Aspect J'yi kullanmak ve oluşturmaktırAdvice
Hima

12

Buna verilen tüm yanıtlar, WebMvcInterface (@sebdooe tarafından belirtildiği gibi) yerine artık uzun süredir kullanımdan kaldırılmış soyut WebMvcConfigurer Bağdaştırıcısını kullandığından, burada Interceptor'lı bir SpringBoot (2.1.4) uygulaması için minimum çalışan bir örnek verilmiştir:

Minimal.java:

@SpringBootApplication
public class Minimal
{
    public static void main(String[] args)
    {
        SpringApplication.run(Minimal.class, args);
    }
}

MinimalController.java:

@RestController
@RequestMapping("/")
public class Controller
{
    @GetMapping("/")
    @ResponseBody
    public ResponseEntity<String> getMinimal()
    {
        System.out.println("MINIMAL: GETMINIMAL()");

        return new ResponseEntity<String>("returnstring", HttpStatus.OK);
    }
}

Config.java:

@Configuration
public class Config implements WebMvcConfigurer
{
    //@Autowired
    //MinimalInterceptor minimalInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry)
    {
        registry.addInterceptor(new MinimalInterceptor());
    }
}

MinimalInterceptor.java:

public class MinimalInterceptor extends HandlerInterceptorAdapter
{
    @Override
    public boolean preHandle(HttpServletRequest requestServlet, HttpServletResponse responseServlet, Object handler) throws Exception
    {
        System.out.println("MINIMAL: INTERCEPTOR PREHANDLE CALLED");

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
    {
        System.out.println("MINIMAL: INTERCEPTOR POSTHANDLE CALLED");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception
    {
        System.out.println("MINIMAL: INTERCEPTOR AFTERCOMPLETION CALLED");
    }
}

reklamı yapıldığı gibi çalışır

Çıktı size şöyle bir şey verecektir:

> Task :Minimal.main()

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.4.RELEASE)

2019-04-29 11:53:47.560  INFO 4593 --- [           main] io.minimal.Minimal                       : Starting Minimal on y with PID 4593 (/x/y/z/spring-minimal/build/classes/java/main started by x in /x/y/z/spring-minimal)
2019-04-29 11:53:47.563  INFO 4593 --- [           main] io.minimal.Minimal                       : No active profile set, falling back to default profiles: default
2019-04-29 11:53:48.745  INFO 4593 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-04-29 11:53:48.780  INFO 4593 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-04-29 11:53:48.781  INFO 4593 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-04-29 11:53:48.892  INFO 4593 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-04-29 11:53:48.893  INFO 4593 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1269 ms
2019-04-29 11:53:49.130  INFO 4593 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-29 11:53:49.375  INFO 4593 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-29 11:53:49.380  INFO 4593 --- [           main] io.minimal.Minimal                       : Started Minimal in 2.525 seconds (JVM running for 2.9)
2019-04-29 11:54:01.267  INFO 4593 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-04-29 11:54:01.267  INFO 4593 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2019-04-29 11:54:01.286  INFO 4593 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 19 ms
MINIMAL: INTERCEPTOR PREHANDLE CALLED
MINIMAL: GETMINIMAL()
MINIMAL: INTERCEPTOR POSTHANDLE CALLED
MINIMAL: INTERCEPTOR AFTERCOMPLETION CALLED

Ancak bu, WebMvcConfigurer'daki tüm yöntemleri uygulamanızı gerektirecek, değil mi?
Steven

Hayır, boş varsayılan uygulamaları olan bir (Java 8) arayüzü
Tom

9

Kullanımdan kaldırılan WebMvcConfigurerAdapter ile aynı sorunu yaşadım. Örnekler aradığımda neredeyse hiç uygulanmış kod bulamadım. İşte bir çalışma kodu.

HandlerInterceptorAdapter öğesini genişleten bir sınıf oluşturun

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import me.rajnarayanan.datatest.DataTestApplication;
@Component
public class EmployeeInterceptor extends HandlerInterceptorAdapter {
    private static final Logger logger = LoggerFactory.getLogger(DataTestApplication.class);
    @Override
    public boolean preHandle(HttpServletRequest request, 
            HttpServletResponse response, Object handler) throws Exception {

            String x = request.getMethod();
            logger.info(x + "intercepted");
        return true;
    }

}

sonra WebMvcConfigurer arabirimini uygulayın

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import me.rajnarayanan.datatest.interceptor.EmployeeInterceptor;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    EmployeeInterceptor employeeInterceptor ;

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(employeeInterceptor).addPathPatterns("/employee");
    }
}

4
Derleme sorunları olmadan bir arayüzde yalnızca bir yöntemi nasıl geçersiz kılabilirsiniz?
xetra11

1
@ xetra11 Bu durumda kullanılmayan diğer tüm yöntemler yerine yalnızca bir yöntemi uygulayıp uygulayamayacağımızı da görmeye çalışıyorum. Mümkün mü? Bunu çözdün mü?
user09

3
@arjun Diğerleri Java 8 sayesinde varsayılan yöntemler olarak uygulanmaktadır . Bu mantık, uygun bir şekilde, kullanımdan kaldırılan sınıfta belgelenmiştir .
Bob

8

Ayrıca, tıpkı url rotalarınıza açıklama eklediğiniz gibi, hangi durdurucuların uygulanacağına Spring Boot denetleyicilerinize doğrudan açıklama eklemenize olanak tanıyan açık kaynak SpringSandwich kitaplığını kullanmayı da düşünebilirsiniz.

Bu şekilde, yazım hatasına yatkın Dizeler ortalıkta gezinmez - SpringSandwich'in yöntemi ve sınıf ek açıklamaları yeniden düzenlemeden kolayca kurtulabilir ve neyin nerede uygulandığını netleştirebilir. (Açıklama: Ben yazarım).

http://springsandwich.com/


Harika görünüyor! CI altında inşa edilen veya Heroku aracılığıyla dağıtılan projelerde kullanımı kolaylaştırmak için SpringSandwich'in maven merkezinde kullanılabilir olmasını isteyen bir sorun oluşturdum.
Brendon Dugan

Harika. Maven merkezi deposunda mevcut mu? Re - springsandwich.com'u git deponuz ve referansınız ile web sitemde bloglama
Arpan Das

1
SpringSandwich şimdi Maven Central'da
Magnus

0

Aşağıda, her HTTP isteğini, dışarı çıkmadan ve geri gelen yanıtı kesmeden önce durdurmak için kullandığım bir uygulama var. Bu uygulama ile ayrıca istek ile herhangi bir başlık değerini iletebileceğim tek bir noktam var.

public class HttpInterceptor implements ClientHttpRequestInterceptor {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public ClientHttpResponse intercept(
        HttpRequest request, byte[] body,
        ClientHttpRequestExecution execution
) throws IOException {
    HttpHeaders headers = request.getHeaders();
    headers.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
    headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
    traceRequest(request, body);
    ClientHttpResponse response = execution.execute(request, body);
    traceResponse(response);
    return response;
}

private void traceRequest(HttpRequest request, byte[] body) throws IOException {
    logger.info("===========================Request begin======================================");
    logger.info("URI         : {}", request.getURI());
    logger.info("Method      : {}", request.getMethod());
    logger.info("Headers     : {}", request.getHeaders() );
    logger.info("Request body: {}", new String(body, StandardCharsets.UTF_8));
    logger.info("==========================Request end=========================================");
}

private void traceResponse(ClientHttpResponse response) throws IOException {
    logger.info("============================Response begin====================================");
    logger.info("Status code  : {}", response.getStatusCode());
    logger.info("Status text  : {}", response.getStatusText());
    logger.info("Headers      : {}", response.getHeaders());
    logger.info("=======================Response end===========================================");
}}

Aşağıda Kalan Şablon Fasulyesi var

@Bean
public RestTemplate restTemplate(HttpClient httpClient)
{
    HttpComponentsClientHttpRequestFactory requestFactory =
            new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);
    RestTemplate restTemplate=  new RestTemplate(requestFactory);
    List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
    if (CollectionUtils.isEmpty(interceptors))
    {
        interceptors = new ArrayList<>();
    }
    interceptors.add(new HttpInterceptor());
    restTemplate.setInterceptors(interceptors);

    return restTemplate;
}

1
Tamam ama burada gerçekte yaptığınız şey, RestTemplate için bir engelleyici (yani, HTTP çağrıları yaptığınızda) ... Spring REST Denetleyicileri için bir engelleyici değil (yani, Spring uygulamanıza / REST-web hizmetlerine karşı HTTP çağrıları yapıldığında).
maxxyme
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.