Zoeken…


Opmerkingen

In tegenstelling tot SOAP en de WS-stack, die worden gespecificeerd als W3C-normen, is REST echt een set principes voor het ontwerpen en gebruiken van een webgebaseerde interface. REST / RESTful-applicaties zijn sterk afhankelijk van andere normen:

HTTP
URI, URL
XML, JSON, HTML, GIF, JPEG, and so forth (resource representations)

De rol van JAX-RS (Java API voor RESTful Web Services) is om API's te bieden die het bouwen van RESTful-services ondersteunen. JAX-RS is echter slechts een manier om dit te doen . RESTful-services kunnen op andere manieren in Java worden geïmplementeerd, en (inderdaad) in vele andere programmeertalen.

Eenvoudige bron

Allereerst moet voor een JAX-RS-toepassing een basis-URI worden ingesteld van waaruit alle bronnen beschikbaar zullen zijn. Voor dat doel moet de klasse javax.ws.rs.core.Application worden uitgebreid en geannoteerd met de annotatie javax.ws.rs.ApplicationPath . De annotatie accepteert een stringargument dat de basis-URI definieert.

@ApplicationPath(JaxRsActivator.ROOT_PATH)
public class JaxRsActivator extends Application {

    /**
     * JAX-RS root path.
     */
    public static final String ROOT_PATH = "/api";

}

Bronnen zijn eenvoudige POJO- klassen die zijn geannoteerd met de @Path annotatie.

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/hello")
public class HelloWorldResource {
    public static final String MESSAGE = "Hello StackOverflow!";

    @GET
    @Produces("text/plain")
    public String getHello() {
        return MESSAGE;
    }
}

Wanneer een HTTP GET verzoek wordt verzonden naar /hello , reageert de resource met een Hello StackOverflow! bericht.

GET-methode types

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/hello")
public class HelloWorldResource {
    public static final String MESSAGE = "Hello World!";

    @GET
    @Produces("text/plain")
    public String getHello() {
        return MESSAGE;
    }

    @GET
    @Path("/{letter}")
    @Produces("text/plain")
    public String getHelloLetter(@PathParam("letter") int letter){
        if (letter >= 0 && letter < MESSAGE.length()) {
            return MESSAGE.substring(letter, letter + 1);
        } else {
            return "";
        }
    }
}

GET zonder parameter geeft alle inhoud ("Hallo wereld!") En GET met parameter path geeft de specifieke letter uit die string.

Een paar voorbeelden:

$ curl http://localhost/hello
Hello World!
$ curl http://localhost/hello/0
H
$ curl http://localhost/hello/4
o

Opmerking: als u de annotatie van het methode-type (bijvoorbeeld de @GET hierboven) @GET , is een aanvraagmethode standaard een GET-aanvraaghandler.

VERWIJDER methode

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;

@Path("hello")
public class HelloWorldResource {

    private String message = "Hello StackOverflow!";

    @GET
    @Produces("text/plain")
    public String getHello() {
        return message;
    }

    @DELETE
    public Response deleteMessage() {
        message = null;
        return Response.noContent().build();
    }
}

Consumeer het met krul:

$ curl http://localhost/hello
Hello StackOverflow!

$ curl -X "DELETE" http://localhost/hello


$ curl http://localhost/hello
null

POST-methode

import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

@Path("hello")
public class HelloWorldResource {
    @POST
    @Path("/receiveParams")
    public Response receiveHello(@FormParam("name") String name, @FormParam("message") String message) {
        //process parameters
        return Response.status(200).build();
    }

    @POST
    @Path("/saveObject")
    @Consumes("application/json")
    public Response saveMessage(Message message) {
        //process message json
        return Response.status(200).entity("OK").build();
    }
}

De eerste methode kan worden opgeroepen via HTML-formulierverzending door vastgelegde invoerparameters te verzenden. Formulier indienen actie moet wijzen op -

/hello/receiveParams

Tweede methode vereist Message POJO met getters / setters. Elke REST-client kan deze methode met JSON-invoer aanroepen als -

{"sender":"someone","message":"Hello SO!"}

POJO moet dezelfde eigenschap hebben als JSON om serialisatie te laten werken.

public class Message {

    String sender;
    String message;

    public String getSender() {
        return sender;
    }
    public void setSender(String sender) {
        this.sender = sender;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}

Uitzondering Mapper

@Provider
public class IllegalArgumentExceptionMapper implements ExceptionMapper<IllegalArgumentException> {
        
  @Override
  public Response toResponse(IllegalArgumentException exception) {
    return Response.serverError().entity("Invalid input: " + exception.getMessage()).build();
  }
}

Deze uitzonderingsmap zal alle IllegalArgumentExceptions in de toepassing vangen en de gebruiker een duidelijk bericht laten zien in plaats van een stacktrace.

UriInfo

Om informatie te krijgen over de URI die de user-agent heeft gebruikt om toegang te krijgen tot uw bron, kunt u de @Context parameter @Context gebruiken met een UriInfo parameter. Het UriInfo object heeft een paar methoden die kunnen worden gebruikt om verschillende delen van de URI te krijgen.

//server is running on https://localhost:8080,
// webapp is at /webapp, servlet at /webapp/servlet
@Path("class")
class Foo {
    
    @GET
    @Path("resource")
    @Produces(MediaType.TEXT_PLAIN)
    public Response getResource(@Context UriInfo uriInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append("Path: " + uriInfo.getPath() + "\n");
        sb.append("Absolute Path: " + uriInfo.getAbsolutePath() + "\n");
        sb.append("Base URI: " + uriInfo.getBaseUri() + "\n");
        sb.append("Request URI: " + uriInfo.getRequestUri() + "\n");
        return Response.ok(sb.toString()).build();
    }
}

output van een GET naar https://localhost:8080/webapp/servlet/class/resource :

Path: class/resource
Absolute Path: https://localhost:8080/webapp/servlet/class/resource#
Base URI: https://localhost:8080/webapp/servlet/
Request URI: https://localhost:8080/webapp/servlet/class/resource

SubResources

Soms is het om organisatorische of andere redenen logisch dat uw resource op het hoogste niveau een subresource retourneert die er zo uitziet. (Uw subresource hoeft geen binnenklasse te zijn)

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("items")
public class ItemsResource {

    @Path("{id}")
    public String item(@PathParam("id") String id) {
        return new ItemSubResource(id);
    }

    public static class ItemSubResource {

        private final String id;

        public ItemSubResource(String id) {
            this.id = id;
        }
        
        @GET
        @Produces("text/plain")
        public Item item() {
            return "The item " + id;
        }
    }
}

Aangepaste parameterconverters

Dit is een voorbeeld van het implementeren van aangepaste parameterconverters voor JAX-RS-eindpunten. Het voorbeeld toont twee klassen van Java 8 's java.time bibliotheek.

@Provider
public class ParamConverters implements ParamConverterProvider {  
  @Override
  public <T> ParamConverter<T> getConverter(Class<T> rawType,
                                            Type genericType,
                                            Annotation[] annotations)
  {
    if (rawType == LocalDate.class)
      return (ParamConverter<T>) new ParamConverter<LocalDate>() {
        @Override
        public LocalDate fromString(String value) {
          return LocalDate.parse(value);
        }

        @Override
        public String toString(LocalDate value) {
          return null;
        }
      };
    else if (rawType == MonthDay.class)
      return (ParamConverter<T>) new ParamConverter<MonthDay>() {
        @Override
        public MonthDay fromString(String value) {
          int[] ddmm = Arrays.stream(value.split("/"))
                             .mapToInt(Integer::parseInt)
                             .toArray();
          return MonthDay.of(ddmm[1], ddmm[0]);
        }

        @Override
        public String toString(MonthDay value) {
          return null;
        }
      };
    return null;
  }
}

Naam bindend

Naambinding is een concept waarmee tegen een JAX-RS runtime kan worden gezegd dat een specifiek filter of interceptor alleen voor een specifieke resourcemethode wordt uitgevoerd. Wanneer een filter of een interceptor alleen beperkt is tot een specifieke bronmethode, zeggen we dat deze naamgebonden is . Filters en interceptors die geen dergelijke beperking hebben, worden globaal genoemd .

Een bindende annotatie voor de naam definiëren

Filters of interceptors kunnen worden toegewezen aan een @NameBinding met behulp van de annotatie @NameBinding . Deze annotatie wordt gebruikt als meta-annotatie voor andere door gebruikers geïmplementeerde annotaties die worden toegepast op providers en resourcemethoden. Zie het volgende voorbeeld:

@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Compress {}

Het bovenstaande voorbeeld definieert een nieuwe @Compress annotatie die een @Compress annotatie is zoals deze is geannoteerd met @NameBinding . De annotatie @Compress kan worden gebruikt om filters en interceptor aan eindpunten te binden.

Een filter of interceptor aan een eindpunt binden

Overweeg dat u een interceptor hebt die GZIP-compressie uitvoert en dat u een dergelijke interceptor aan een bronmethode wilt binden. Om dit te doen, annoteert u zowel de bronmethode als de interceptor als volgt:

@Compress
public class GZIPWriterInterceptor implements WriterInterceptor {

    @Override
    public void aroundWriteTo(WriterInterceptorContext context)
                    throws IOException, WebApplicationException {
        final OutputStream outputStream = context.getOutputStream();
        context.setOutputStream(new GZIPOutputStream(outputStream));
        context.proceed();
    }
}
@Path("helloworld")
public class HelloWorldResource {
 
    @GET
    @Produces("text/plain")
    public String getHello() {
        return "Hello World!";
    }
 
    @GET
    @Path("too-much-data")
    @Compress
    public String getVeryLongString() {
        String str = ... // very long string
        return str;
    }
}

De @Compress wordt toegepast op de getVeryLongString() en op de interceptor GZIPWriterInterceptor . De interceptor wordt alleen uitgevoerd als een bronmethode met een dergelijke annotatie wordt uitgevoerd.

In het bovenstaande voorbeeld wordt de interceptor alleen uitgevoerd voor de methode getVeryLongString() . De interceptor wordt niet uitgevoerd voor methode getHello() . In dit voorbeeld is de reden waarschijnlijk duidelijk. We willen alleen lange gegevens comprimeren en we hoeven de korte reactie van "Hello World!" Niet te comprimeren "Hello World!" .

Naambinding kan worden toegepast op een resourceklasse. In het voorbeeld zou HelloWorldResource worden geannoteerd met @Compress . Dit zou betekenen dat alle bronmethoden in dit geval compressie zullen gebruiken.

Merk op dat globale filters altijd worden uitgevoerd, dus zelfs voor bronmethoden die een naam bindende annotaties hebben.

Documentatie



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow