2015-01-29 30 views
12

Próbuję odczytać nagłówki HTTP w Spring REST API. Poszłam za this. Ale dostaję ten błąd:Odczytywanie nagłówków HTTP w kontrolerze REST wiosny

No message body reader has been found for class java.lang.String,
ContentType: application/octet-stream

Jestem nowy w Java i Spring, więc nie mogę tego zrozumieć.

To jest jak moja rozmowa wygląda następująco:

@WebService(serviceName = "common") 
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) 
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) 
public interface CommonApiService { 

    @GET 
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED) 
    @Produces(MediaType.APPLICATION_JSON) 
    @Path("/data") 
    public ResponseEntity<Data> getData(@RequestHeader(value="User-Agent") String userAgent, @DefaultValue ("") @QueryParam("ID") String id); 
} 

Próbowałem @Context: HTTPHeader jest null w tym przypadku.

Jak uzyskać wartości z nagłówków HTTP?

+0

Twoje rzeczywiste żądanie jest wysyłane jako "aplikacja/strumień-oktetu", którego Spring nie może przekształcić z powrotem w typ danych String. Ustaw to na 'application/json' (jeśli masz Jacksona na ścieżce klasy) lub cokolwiek spodziewasz się skonsumować i być może uda ci się gdzieś dostać. Czy przypadkiem próbujesz załadować plik do kontrolera REST? – JamesENL

+0

Korzystam z usługi Google Listonosza, aby wykonać połączenie. Ustawiam typ zawartości na application/json i wciąż otrzymuję błąd. –

Odpowiedz

31

Wystąpił błąd, który wydaje się nie być związany z RequestHeader.

I to wydaje się być mylące usługi Wiosna spoczywać JAX-RS, podpis metoda powinna być czymś w rodzaju:

@RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "data") 
@ResponseBody 
public ResponseEntity<Data> getData(@RequestHeader(value="User-Agent") String userAgent, @RequestParam(value = "ID", defaultValue = "") String id) { 
    // your code goes here 
} 

I klasy Reszta powinna mieć adnotacje, takie jak:

@Controller 
@RequestMapping("/rest/") 


chodzi Właściwe pytanie, innym sposobem na uzyskanie nagłówków HTTP jest wstawienie HttpServletRequest do swojej metody, a następnie pobranie żądanego nagłówka.

Przykład:

@RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "data") 
@ResponseBody 
public ResponseEntity<Data> getData(HttpServletRequest request, @RequestParam(value = "ID", defaultValue = "") String id) { 
    String userAgent = request.getHeader("user-agent"); 
} 

Nie martw się o wstrzyknięciu HttpServletRequest bo wiosna robi, że magia dla Ciebie;)

+0

Zaktualizowano pytanie. –

+0

Nadal mieszacie ramy, próbujesz użyć jax-rs AND Spring reszta. Wygląd i moje i odpowiedź @JamesMassey w celu korzystania z api spoczynku wiosny. –

5

mam zamiar dać wam przykład jak ja przeczytaj nagłówki REST dla moich kontrolerów. Moje kontrolery akceptują tylko aplikację/json jako typ żądania, jeśli mam dane, które należy odczytać. Podejrzewam, że twój problem polega na tym, że masz strumień aplikacji/oktetu, którego Spring nie potrafi obsłużyć.

Normalnie moje kontrolery wyglądać następująco:

@Controller 
public class FooController { 
    @Autowired 
    private DataService dataService; 

    @RequestMapping(value="/foo/", method = RequestMethod.GET) 
    @ResponseBody 
    public ResponseEntity<Data> getData(@RequestHeader String dataId){ 
     return ResponseEntity.newInstance(dataService.getData(dataId); 
    } 

Teraz jest dużo kodu robi rzeczy w tle tu więc będę rozbicie go dla Ciebie.

ResponseEntity jest niestandardowym obiektem, który zwracany jest każdy kontroler. Zawiera statyczną fabrykę umożliwiającą tworzenie nowych instancji. Moja usługa danych jest standardową klasą usług.

Magia dzieje się za kulisami, ponieważ pracujesz z JSON, musisz powiedzieć Springowi, aby użył Jacksona do odwzorowania obiektów HttpRequest, aby wiedział, z czym masz do czynienia.

Można to zrobić poprzez określenie to wewnątrz bloku <mvc:annotation-driven> swojej config

<mvc:annotation-driven> 
    <mvc:message-converters> 
     <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
      <property name="objectMapper" ref="objectMapper" /> 
     </bean> 
    </mvc:message-converters> 
</mvc:annotation-driven> 

ObjectMapper jest po prostu przedłużeniem com.fasterxml.jackson.databind.ObjectMapper i co Jackson wykorzystuje faktycznie map żądania od JSON do obiektu.

Podejrzewam, że otrzymujesz wyjątek, ponieważ nie określiłeś elementu odwzorowującego, który może odczytać strumień Oktetowy w obiekcie lub coś, co Spring może obsłużyć. Jeśli próbujesz przesłać plik, jest to coś zupełnie innego.

Moja prośba wysłana do kontrolera wygląda w ten sposób po prostu ma dodatkowy nagłówek o nazwie dataId.

Jeśli chcesz to zmienić, aby parametru żądania i używać @RequestParam String dataId aby odczytać identyfikator z zamówienie będzie wyglądać podobnie do tego:

contactId : {"fooId"} 

Parametr ten wniosek może być tak skomplikowane, jak chcesz . Możesz serializować cały obiekt w JSON, wysłać go jako parametr żądania, a Spring serializuje go (używając Jackson) z powrotem do obiektu Java, który jest gotowy do użycia.

Przykład kontrolera:

@RequestMapping(value = "/penguin Details/", method = RequestMethod.GET) 
@ResponseBody 
public DataProcessingResponseDTO<Pengin> getPenguinDetailsFromList(
     @RequestParam DataProcessingRequestDTO jsonPenguinRequestDTO) 

Zapytanie Wysłane:

jsonPengiunRequestDTO: { 
    "draw": 1, 
    "columns": [ 
     { 
      "data": { 
       "_": "toAddress", 
       "header": "toAddress" 
      }, 
      "name": "toAddress", 
      "searchable": true, 
      "orderable": true, 
      "search": { 
       "value": "", 
       "regex": false 
      } 
     }, 
     { 
      "data": { 
       "_": "fromAddress", 
       "header": "fromAddress" 
      }, 
      "name": "fromAddress", 
      "searchable": true, 
      "orderable": true, 
      "search": { 
       "value": "", 
       "regex": false 
      } 
     }, 
     { 
      "data": { 
       "_": "customerCampaignId", 
       "header": "customerCampaignId" 
      }, 
      "name": "customerCampaignId", 
      "searchable": true, 
      "orderable": true, 
      "search": { 
       "value": "", 
       "regex": false 
      } 
     }, 
     { 
      "data": { 
       "_": "penguinId", 
       "header": "penguinId" 
      }, 
      "name": "penguinId", 
      "searchable": false, 
      "orderable": true, 
      "search": { 
       "value": "", 
       "regex": false 
      } 
     }, 
     { 
      "data": { 
       "_": "validpenguin", 
       "header": "validpenguin" 
      }, 
      "name": "validpenguin", 
      "searchable": true, 
      "orderable": true, 
      "search": { 
       "value": "", 
       "regex": false 
      } 
     }, 
     { 
      "data": { 
       "_": "", 
       "header": "" 
      }, 
      "name": "", 
      "searchable": false, 
      "orderable": false, 
      "search": { 
       "value": "", 
       "regex": false 
      } 
     } 
    ], 
    "order": [ 
     { 
      "column": 0, 
      "dir": "asc" 
     } 
    ], 
    "start": 0, 
    "length": 10, 
    "search": { 
     "value": "", 
     "regex": false 
    }, 
    "objectId": "30" 
} 

który zostanie automatycznie szeregowane z powrotem do obiektu DataProcessingRequestDTO przed uzyskaniem do kontrolera dla mnie gotowe do użycia.

Jak widać, jest to dość potężne, co pozwala na szeregowanie danych z JSON do obiektu bez konieczności pisania pojedynczego wiersza kodu. Możesz to zrobić dla @RequestParam i @RequestBody, co pozwala ci uzyskać dostęp do JSON wewnątrz swoich parametrów lub ciała żądania odpowiednio.

Teraz, gdy masz konkretny przykład, aby wyjść, po zmianie typu zgłoszenia nie powinieneś mieć żadnych problemów z numerem application/json.