Http Message Converters met het Spring Framework

1. Overzicht

Dit artikel beschrijft hoe te configureren HttpMessageConverters in de lente.

Simpel gezegd, we kunnen berichtconversieprogramma's gebruiken om Java-objecten van en naar JSON, XML, enz. Via HTTP te rangschikken en te verwijderen.

2. De basis

2.1. Schakel Web MVC in

Om te beginnen moet de webapplicatie geconfigureerd met Spring MVC-ondersteuning. Een handige en zeer aanpasbare manier om dit te doen, is door de @EnableWebMvc annotatie:

@EnableWebMvc @Configuration @ComponentScan ({"com.baeldung.web"}) openbare klasse Webconfiguratie implementeert WebMvcConfigurer {...}

Merk op dat deze klasse implementeert WebMvcConfigurer - waarmee we de standaardlijst met Http-converters kunnen wijzigen met de onze.

2.2. De standaard berichtconverters

Standaard zijn de volgende HttpMessageConverter s instanties zijn vooraf ingeschakeld:

  • ByteArrayHttpMessageConverter - converteert byte-arrays
  • StringHttpMessageConverter - converteert Strings
  • ResourceHttpMessageConverter - bekeert org.springframework.core.io.Resource voor elk type octet-stream
  • SourceHttpMessageConverter - bekeert javax.xml.transform.Source
  • FormHttpMessageConverter - converteert formuliergegevens van / naar een MultiValueMap.
  • Jaxb2RootElementHttpMessageConverter - converteert Java-objecten van / naar XML (alleen toegevoegd als JAXB2 aanwezig is op het klassenpad)
  • Toewijzing Jackson2HttpMessageConverter - converteert JSON (alleen toegevoegd als Jackson 2 aanwezig is op het klassenpad)

  • Toewijzing JacksonHttpMessageConverter - converteert JSON (alleen toegevoegd als Jackson aanwezig is op het klassenpad)
  • AtomFeedHttpMessageConverter - converteert Atom-feeds (alleen toegevoegd als Rome aanwezig is op het klassenpad)
  • RssChannelHttpMessageConverter - converteert RSS-feeds (alleen toegevoegd als Rome aanwezig is op het klassenpad)

3. Client-server-communicatie - alleen JSON

3.1. Onderhandelen over inhoud op hoog niveau

Elk HttpMessageConverter implementatie heeft een of meer bijbehorende MIME-typen.

Als u een nieuw verzoek ontvangt, De lente zal de “Aanvaarden”Om het mediatype te bepalen waarmee het moet reageren.

Het zal dan proberen een geregistreerde converter te vinden die geschikt is voor dat specifieke mediatype. Ten slotte zal het dit gebruiken om de entiteit te converteren en het antwoord terug te sturen.

Het proces is vergelijkbaar voor het ontvangen van een verzoek dat JSON-informatie bevat. Het raamwerk zal gebruik de "Inhoudstype”Om het mediatype van de hoofdtekst van het verzoek te bepalen.

Het zoekt dan naar een HttpMessageConverter die de door de client verzonden body kan converteren naar een Java-object.

Laten we dit verduidelijken met een snel voorbeeld:

  • de klant stuurt een GET-verzoek naar / foos met de Aanvaarden header ingesteld op applicatie / json - om alles te krijgen Foo resources als JSON
  • de Foo Spring Controller wordt geraakt en retourneert het overeenkomstige Foo Java-entiteiten
  • Spring gebruikt vervolgens een van de Jackson-berichtconversieprogramma's om de entiteiten naar JSON te leiden

Laten we nu kijken naar de details van hoe dit werkt - en hoe we het @ResponseBody en @RequestBody annotaties.

3.2. @ResponseBody

@ResponseBody op een Controller-methode geeft aan Spring dat de geretourneerde waarde van de methode wordt rechtstreeks naar de hoofdtekst van de HTTP-respons geserialiseerd. Zoals hierboven besproken, de "Aanvaarden”Header gespecificeerd door de klant zal worden gebruikt om de juiste Http Converter te kiezen om de entiteit te rangschikken.

Laten we naar een eenvoudig voorbeeld kijken:

@GetMapping ("/ {id}") openbaar @ResponseBody Foo findById (@PathVariable lange id) {return fooService.findById (id); }

Nu zal de client de "Accept" -header specificeren naar applicatie / json in het verzoek - voorbeeld krullen opdracht:

curl --header "Accept: application / json" // localhost: 8080 / spring-boot-rest / foos / 1

De Foo klasse:

openbare klasse Foo {lange privé-id; private String naam; }

En de Http Response Body:

{"id": 1, "name": "Paul",}

3.3. @RequestBody

We kunnen de @RequestBody annotatie op het argument van een Controller-methode om aan te geven dat de body van het HTTP-verzoek wordt gedeserialiseerd naar die specifieke Java-entiteit. Om de juiste converter te bepalen, gebruikt Spring de "Content-Type" -header van het clientverzoek.

Laten we naar een voorbeeld kijken:

@PutMapping ("/ {id}") openbare @ResponseBody ongeldige update (@RequestBody Foo foo, @PathVariable String id) {fooService.update (foo); }

Laten we dit vervolgens consumeren met een JSON-object - we specificeren “Content-Type zijn applicatie / json:

curl -i -X ​​PUT -H "Content-Type: application / json" -d '{"id": "83", "name": "klik"}' // localhost: 8080 / spring-boot-rest / foos / 1

We krijgen een 200 OK terug - een succesvol antwoord:

HTTP / 1.1 200 OK Server: Apache-Coyote / 1.1 Inhoud-lengte: 0 Datum: vr, 10 jan 2014 11:18:54 GMT

4. Aangepaste configuratie van converters

We kunnen ook pas de berichtconversieprogramma's aan door het WebMvcConfigurer koppel en het negeren van de configureMessageConverters methode:

@EnableWebMvc @Configuration @ComponentScan ({"com.baeldung.web"}) public class Webconfiguratie implementeert WebMvcConfigurer {@Override public void configureMessageConverters (lijst converters) {messageConverters.add (createXmlHttpMessageConverter ()); messageConverters.add (nieuwe MappingJackson2HttpMessageConverter ()); } privé HttpMessageConverter createXmlHttpMessageConverter () {MarshallingHttpMessageConverter xmlConverter = nieuwe MarshallingHttpMessageConverter (); XStreamMarshaller xstreamMarshaller = nieuwe XStreamMarshaller (); xmlConverter.setMarshaller (xstreamMarshaller); xmlConverter.setUnmarshaller (xstreamMarshaller); retourneer xmlConverter; }}

In dit voorbeeld maken we een nieuwe converter: de MarshallingHttpMessageConverter - en de Spring XStream-ondersteuning gebruiken om het te configureren. Dit biedt sindsdien veel flexibiliteit we werken met de low-level API's van het onderliggende marshalling-framework - in dit geval XStream - en we kunnen dat configureren zoals we willen.

Merk op dat voor dit voorbeeld de XStream-bibliotheek aan het klassenpad moet worden toegevoegd.

Houd er ook rekening mee dat door deze ondersteuningsklasse uit te breiden, we verliezen de standaard berichtconverters die eerder vooraf waren geregistreerd.

We kunnen nu natuurlijk hetzelfde doen voor Jackson - door de onze te definiëren ToewijzingJackson2HttpMessageConverter. We kunnen nu een gewoonte instellen ObjectMapper op deze converter en laat deze configureren zoals we nodig hebben.

In dit geval was XStream de geselecteerde marshaller / unmarshaller-implementatie, maar anderen houden van CastorMarshaller kan ook worden gebruikt.

Op dit punt - met XML ingeschakeld aan de achterkant - kunnen we de API gebruiken met XML-representaties:

curl --header "Accept: application / xml" // localhost: 8080 / spring-boot-rest / foos / 1

4.1. Spring Boot-ondersteuning

Als we Spring Boot gebruiken, kunnen we voorkomen dat het WebMvcConfigurer en het handmatig toevoegen van alle Message Converters zoals we hierboven hebben gedaan.

We kunnen gewoon anders definiëren HttpMessageConverter bonen in de context, en Spring Boot zal ze automatisch toevoegen aan de autoconfiguratie die het maakt:

@Bean openbare HttpMessageConverter createXmlHttpMessageConverter () {MarshallingHttpMessageConverter xmlConverter = nieuwe MarshallingHttpMessageConverter (); // ... retourneer xmlConverter; }

5. Spring's gebruiken RestTemplate Met HTTP-berichtconverters

Evenals met de serverkant, kan Http Message Conversion worden geconfigureerd aan de clientkant op de Spring RestTemplate.

We gaan de sjabloon configureren met de "Aanvaarden"En"Inhoudstype”Kopteksten indien van toepassing. Vervolgens zullen we proberen de REST API te gebruiken met volledige rangschikking en unmarshalling van de Foo Resource - zowel met JSON als met XML.

5.1. De bron ophalen met nr Aanvaarden Header

@Test public void testGetFoo () {String URI = "// localhost: 8080 / spring-boot-rest / foos / {id}"; RestTemplate restTemplate = new RestTemplate (); Foo foo = restTemplate.getForObject (URI, Foo. class, "1"); Assert.assertEquals (new Integer (1), foo.getId ());}

5.2. Een bron ophalen met application / xml Accepteer koptekst

Laten we nu expliciet de bron ophalen als een XML-weergave. We gaan een set converters definiëren en deze op de RestTemplate.

Omdat we XML gebruiken, gaan we dezelfde XStream-marshaller gebruiken als voorheen:

@Test openbare ongeldig gegevenConsumingXml_whenReadingTheFoo_thenCorrect () {String URI = BASE_URI + "foos / {id}"; RestTemplate restTemplate = nieuwe RestTemplate (); restTemplate.setMessageConverters (getMessageConverters ()); HttpHeaders headers = nieuwe HttpHeaders (); headers.setAccept (Arrays.asList (MediaType.APPLICATION_XML)); HttpEntity entity = nieuwe HttpEntity (headers); ResponseEntity response = restTemplate.exchange (URI, HttpMethod.GET, entity, Foo.class, "1"); Foo resource = response.getBody (); assertThat (resource, notNullValue ()); } privélijst getMessageConverters () {XStreamMarshaller marshaller = nieuwe XStreamMarshaller (); MarshallingHttpMessageConverter marshallingConverter = nieuwe MarshallingHttpMessageConverter (marshaller); Lijst converters = ArrayList(); converters.add (marshallingConverter); retour converters; }

5.3. Een bron ophalen met applicatie / json Accepteer koptekst

Evenzo, laten we nu de REST API gebruiken door om JSON te vragen:

@Test openbare leegte gegevenConsumingJson_whenReadingTheFoo_thenCorrect () {String URI = BASE_URI + "foos / {id}"; RestTemplate restTemplate = nieuwe RestTemplate (); restTemplate.setMessageConverters (getMessageConverters ()); HttpHeaders headers = nieuwe HttpHeaders (); headers.setAccept (Arrays.asList (MediaType.APPLICATION_JSON)); HttpEntity entity = nieuwe HttpEntity (headers); ResponseEntity response = restTemplate.exchange (URI, HttpMethod.GET, entity, Foo.class, "1"); Foo resource = response.getBody (); assertThat (resource, notNullValue ()); } privélijst getMessageConverters () {List converters = nieuwe ArrayList(); converters.add (nieuwe MappingJackson2HttpMessageConverter ()); retour converters; }

5.4. Werk een bron bij met XML Inhoudstype

Laten we tot slot ook JSON-gegevens naar de REST API sturen en het mediatype van die gegevens specificeren via de Inhoudstype koptekst:

@Test openbare ongeldig gegevenConsumingXml_whenWritingTheFoo_thenCorrect () {String URI = BASE_URI + "foos / {id}"; RestTemplate restTemplate = nieuwe RestTemplate (); restTemplate.setMessageConverters (getMessageConverters ()); Foo resource = nieuwe Foo (4, "jason"); HttpHeaders headers = nieuwe HttpHeaders (); headers.setAccept (Arrays.asList (MediaType.APPLICATION_JSON)); headers.setContentType ((MediaType.APPLICATION_XML)); HttpEntity entity = nieuwe HttpEntity (resource, headers); ResponseEntity response = restTemplate.exchange (URI, HttpMethod.PUT, entiteit, Foo.class, resource.getId ()); Foo fooResponse = response.getBody (); Assert.assertEquals (resource.getId (), fooResponse.getId ()); }

Wat hier interessant is, is dat we de mediatypen kunnen mixen - we sturen XML-gegevens, maar we wachten op JSON-gegevens terug van de server. Dit laat zien hoe krachtig het conversiemechanisme van de veer werkelijk is.

6. Conclusie

In deze tutorial hebben we gekeken naar hoe Spring MVC ons in staat stelt om Http Message Converters te specificeren en volledig aan te passen aan automatisch Marshall / Unmarshall Java-entiteiten van en naar XML of JSON. Dit is natuurlijk een simplistische definitie, en er is zoveel meer dat het berichtconversiemechanisme kan doen - zoals we kunnen zien in het laatste testvoorbeeld.

We hebben ook gekeken hoe we hetzelfde krachtige mechanisme kunnen gebruiken met de RestTemplate client - wat leidt tot een volledig type-veilige manier om de API te gebruiken.

Zoals altijd is de code die in dit artikel wordt gepresenteerd, beschikbaar op Github.


$config[zx-auto] not found$config[zx-overlay] not found