Sök…


Anmärkningar

Till skillnad från SOAP och WS-stacken, som specificeras som W3C-standarder, är REST verkligen en uppsättning principer för design och användning av webbaserat gränssnitt. REST / RESTful applikationer förlitar sig starkt på andra standarder:

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

Rollen för JAX-RS (Java API för RESTful Web Services) är att tillhandahålla API: er som stöder byggandet av RESTful-tjänster. Men JAX-RS är bara ett sätt att göra detta . RESTful tjänster kan implementeras på andra sätt i Java och (verkligen) på många andra programmeringsspråk.

Enkel resurs

Först för en JAX-RS-applikation måste en bas-URI ställas in från vilken alla resurser kommer att finnas tillgängliga. För detta ändamål javax.ws.rs.core.Application klassen javax.ws.rs.core.Application utvidgas och kommenteras med annotationen javax.ws.rs.ApplicationPath . Anteckningen accepterar ett strängargument som definierar bas-URI.

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

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

}

Resurser är enkla POJO- klasser som kommenteras med @Path kommentaren.

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;
    }
}

När en HTTP GET förfrågan skickas till /hello svarar resursen med Hello StackOverflow! meddelande.

GET-metodtyper

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 utan en parameter ger allt innehåll ("Hej världen!") Och GET med sökvägsparameter ger den specifika bokstaven från den strängen.

Några exempel:

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

Obs: om du lämnar annotationen av @GET (t.ex. @GET ovan), är en begärningsmetod som standard en GET-förfrågningshanterare.

DELETE-metod

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();
    }
}

Konsumera det med lock:

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

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


$ curl http://localhost/hello
null

POST-metod

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();
    }
}

Den första metoden kan åberopas via HTML-formulärinsändning genom att skicka fångade inmatningsparametrar. Åtgärd från formuläret ska peka på -

/hello/receiveParams

Den andra metoden kräver meddelande POJO med getters / seters. Alla REST-klienter kan kalla denna metod med JSON-inmatning som -

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

POJO bör ha samma egenskap som JSON för att göra serienummering fungerar.

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;
    }
}

Exception Mapper

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

Denna undantagsmapper kommer att fånga alla IllegalArgumentExceptions som kastas i applikationen och visa användaren ett tydligt meddelande istället för en stacktrace.

UriInfo

För att få information om URI som användaragenten använde för att få åtkomst till din resurs kan du använda @Context parameteranteckningen med en UriInfo parameter. UriInfo objektet har några metoder som kan användas för att få olika delar av URI.

//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();
    }
}

utgång från en GET till 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

Ibland är det av organisatoriska eller andra skäl vettigt att din resurs på toppnivå returnerar en underresurs som skulle se ut så här. (Din underresurs behöver inte vara en inre klass)

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;
        }
    }
}

Anpassade parameterkonverterare

Detta är ett exempel på hur man implementerar anpassade parameterkonverterare för JAX-RS-slutpunkter. Exemplet visar två klasser från Java 8: s java.time bibliotek.

@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;
  }
}

Namnets bindande

Namnbindning är ett koncept som gör det möjligt att säga till en JAX-RS-runtime att ett specifikt filter eller interceptor kommer att köras endast för en specifik resursmetod. När ett filter eller en interceptor endast är begränsad till en specifik resursmetod säger vi att det är namnbundet . Filter och fångar som inte har en sådan begränsning kallas globala .

Definiera en namnbindande kommentar

Filter eller avlyssnare kan tilldelas en @NameBinding hjälp av anteckningen @NameBinding . Den här kommentaren används som metaanotering för andra användarimplementerade kommentarer som tillämpas på en leverantör och resursmetoder. Se följande exempel:

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

Exemplet ovan definierar en ny @Compress annotation som är en namnbindande annotation eftersom den är kommenterad med @NameBinding . @Compress anteckningen kan användas för att binda filter och interceptor till slutpunkter.

Bindning av ett filter eller avlyssnar till en slutpunkt

Tänk på att du har en interceptor som utför GZIP-komprimering och att du vill binda en sådan interceptor till en resursmetod. För att göra det, anteckna både resursmetoden och interceptorn enligt följande:

@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;
    }
}

@Compress tillämpas på getVeryLongString() och på interceptorn GZIPWriterInterceptor . Interceptorn kommer att köras endast om någon resursmetod med en sådan kommentar kommer att utföras.

I exemplet ovan kommer interceptorn att köras endast för getVeryLongString() . Interceptorn körs inte för metoden getHello() . I detta exempel är orsaken tydlig. Vi vill bara komprimera långa data och vi behöver inte komprimera det korta svaret "Hello World!" .

Namnbindning kan tillämpas på en resursklass. I exemplet skulle HelloWorldResource kommenteras med @Compress . Detta skulle innebära att alla resursmetoder använder komprimering i detta fall.

Observera att globala filter alltid körs, så även för resursmetoder som har några namnbindande kommentarer.

Dokumentation



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow