2017-04-19 82 views
11

Spring-web-4.3.3'ü içeren Spring Boot 1.4.1 kullanıyorum. @ControllerAdvice ile açıklanmış bir sınıfım var ve hizmet kodu tarafından atılan istisnaları işlemek için @ExceptionHandler ile açıklamalı yöntemler. Bu özel durumları ele alırken, PUT ve POST işlemlerinin isteğinin bir parçası olan @RequestBody'u günlüğe kaydetmek istiyorum. Bu nedenle, sorunumda neden olan istek gövdesini tanılama için çok önemli olan sorunu görebiliyorum. yöntemleri için yöntem imzası, HttpServletRequest dahil olmak üzere çeşitli şeyleri içerebilir. İstek gövdesi, buradan getInputStream() veya getReader() aracılığıyla alınabilir, ancak benim denetleyici yöntemlerim tümüyle "@RequestBody Foo fooBody" gibi istek gövdesini ayrıştırıyorsa, HttpServletRequest's giriş akışı veya okuyucu istisna işleyici yöntemim çağrıldığında zaten kapalıdır. Esasen istek gövdesi, here açıklandığı gibi, Spring tarafından zaten okunmuştur. Servletlerle çalışan, talep gövdesinin yalnızca bir kez okunabileceği yaygın bir sorundur.@ExceptionHandler'da (Spring REST) ​​@RequestBody'yi alma

@RequestBody Ne yazık ki bunu kullanabiliyor olsaydı, istisna eylemci yöntemi için kullanılabilen seçeneklerden biri değil.

Özel durum işleyici yöntemine InputStream ekleyebilirim, ancak bu HttpServletRequest'in InputStream ile aynı şeyle sonuçlanır ve bu nedenle de aynı sorunla karşılaşır.

Güncel isteği almayı denediğim başka bir numara olan ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest() ile şu anki isteği almayı denedim, ancak bu durum, Spring'in istisna işleyici yöntemine geçişi ile aynı HttpServletRequest olmasıyla sonuçlanır ve aynı sorunla karşılaşır.

this ve this gibi birkaç çözüm hakkında, filtre zincirine isteklerin içeriğini okuyacak ve bunları bir kez daha okunabilmeleri için önbelleğe alacak özel bir istek sarmalayıcısı eklenmesini içerdiğini okudum. Bu çözümü sevmiyorum çünkü tüm filtreyi/istek/yanıt zincirini (ve potansiyel olarak performans veya kararlılık sorunlarını ortaya koymak için) sadece günlüğe kaydetme uygulamak için istemiyorum ve yüklenen belgeler gibi büyük isteklerim varsa Yaparım, bunu hafızada saklamak istemiyorum. Ayrıca, muhtemelen sadece onu bulabildiysem muhtemelen @RequestBody bir yere önbelleğe sahiptir.

Tesadüfen birçok çözüm, ContentCachingRequestWrapper Spring sınıfını kullanmanızı önerir, ancak deneyimlerimde bu işe yaramıyor. Belgelendirilmemenin yanı sıra, kaynak koduna bakmak, yalnızca parametreleri değil, istek gövdesini önbelleğe alır. İstek sınıfını bu sınıftan almaya çalışırken her zaman boş bir dizeyle sonuçlanır.

Bu yüzden kaçırmış olabileceğim diğer seçenekleri arıyorum. okuduğunuz için teşekkürler.

+0

Yapmak istediğiniz şeyi yapmak için hızlı yerleşik bir çözüm yoktur. Yay talep gövdesini hiçbir yerde önbelleğe almaz. "HandlerMapping" ve "HttpServletRequestWrapper" öğelerini kendiniz oluşturabilirsiniz. –

cevap

2

İstek gövdesi nesnesini isteğe bağlı bir fasülyeye yönlendirebilirsiniz. Ve sonra istek gövdesi (istekte bulunmak istediğiniz diğer istek bağlam fasulye) almak için özel durum işleyicide istek scoped fasulye enjekte edin.

// @Component 
// @Scope("request") 
@ManagedBean 
@RequestScope 
public class RequestContext { 
    // fields, getters, and setters for request-scoped beans 
} 

@RestController 
@RequestMapping("/api/v1/persons") 
public class PersonController { 

    @Inject 
    private RequestContext requestContext; 

    @Inject 
    private PersonService personService; 

    @PostMapping 
    public Person savePerson(@RequestBody Person person) throws PersonServiceException { 
     requestContext.setRequestBody(person); 
     return personService.save(person); 
    } 

} 

@ControllerAdvice 
public class ExceptionMapper { 

    @Inject 
    private RequestContext requestContext; 

    @ExceptionHandler(PersonServiceException.class) 
    protected ResponseEntity<?> onPersonServiceException(PersonServiceException exception) { 
     Object requestBody = requestContext.getRequestBody(); 
     // ... 
     return responseEntity; 
    } 
} 
+1

Evet, sonunda bunu doğrulamak için etrafta dolaştım. "@RequestScope" değil, "@RequestScoped" değil ve tüm POST yöntemlerine bir şeyler eklemek zorundayım, fakat bu istediğim şeyi yapar, cevap için teşekkürler. –

+0

Daha kolay hale getirmek ve organize etmek için, istekte bulunan fasulyeleri istediğiniz tüm uç noktalara çekmek için bir önleme/tavsiye ekleyebilirsiniz. –