Changes

Jax-rs 2.0

9,666 bytes added, 16:25, 26 April 2019
Service osztály definiálása
===Path paraméterek kezelése===<br>===Query paraméterek kezelése===<br> ===Header paraméterek kezelése=== <source lang="java"> @GET @Path("/book/") public Book getBook(@HeaderParam("Authorization") String token) { ...  }</source> <br> ==Response objektum előállítása=manuális összeállítása==
A @GET/POST/PUT annotációkkal ellátott metódusoknál a visszatérési objektum típus meghatározására két lehetőségünk van.
<source lang="java">
@GET
@Path("/contract2contract") public Response getBookContract getContract() {
Contract contract = new Contract();
return contract();
}
</source>
@GET
@Path("/contract2")
public Response getBookgetContract() {
Contract contract = new Contract();
A státuszt kétféle képen határozhatjuk meg A Resonse osztálynak többféle metódusa van, ami beállítja a státuszt: ok=200, created=204 ..., vagy mi állítjuk be kézzel: .status(int)
 
<source lang="java">
public Response getContract() {
...
return Response.status(Status.OK).type(MediaType.APPLICATION_JSON).build();
}
</source>
 
<br>
==Hibakezelés==
A JAX-RS-ben 3 típusa létezik a provider-ekenek, melyekkel három különféle feladatot láthatunk el:
====* Entity provider====
https://docs.huihoo.com/jersey/2.13/message-body-workers.html<br>
The Entity provider API contains 2 interfaces. One for handling inbound entity representation-to-Java de-serialization - '''MessageBodyReader<T>''' and the other one for handling the outbound entity Java-to-representation serialization - '''MessageBodyWriter<T>'''. A MessageBodyReader<T>, as the name suggests, is an extension that supports reading the message body representation from an input stream and converting the data into an instance of a specific Java type. A MessageBodyWriter<T> is then responsible for converting a message payload from an instance of a specific Java type into a specific representation format that is sent over the wire to the other party as part of an HTTP message exchange. Both of these providers can be used to provide message payload serialization and de-serialization support on the server as well as the client side.
 ====* Context provider====
https://www.logicbig.com/tutorials/java-ee-tutorial/jax-rs/context-resolver.html<br>
Context providers supply a context object to resource classes or to other providers.A context provider class must implement the ContextResolver<T>interface.
 ====* Exception provider====
These providers map a checked or runtime exception to an instance of Response. They implement ExceptionMapper<T>. Számunkra ez a lényeges. Itt fogjuk az exception-t
<br><br>
 
===Megvalósítás===
public WebServiceException(String correlationId, String responseMessage, int status, String message, Throwable cause) {
super(message, cause);
...
Használata:
<source lang="java">
@GET
@Path("/contract")
public Contract getContract() {
try {
Contract contract = new Contract();
} catch (Exception e) {
throw new WebServiceException("111", "service-error",404, e.getMessage(), e);
}
return contract;
}
</source>
A válaszban ez így fog megjelenni:<pre>response code: HTTP 404response boy: {"correlationId":"111", "message":"service-error"}</sourcepre>
==Cookie kezelés==
=JAX-RS kliens=
https://dennis-xlc.gitbooks.io/restful-java-with-jax-rs-2-0-en/cn/part1/chapter8/building_and_invoking_requests.html
 
==Kliens bemutatása==
Maven dependecia:
<source lang="java">
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.28</version>
</dependency>
</source>
 
A JAX-RS kliens használata magáért beszél, elég intuitív. A ClientBuilder-el csinálunk egy globális kliens példányt, majd a klienssel készítünk sorban egy target-et, hozzáadunk path-t, request-et, metódust stb... A post(), put() metódusok két paramétert várnak, az első a request body objektum (ha van ilyen az interfészen), a második a válasz típusa. A get() csak egy paramétert vár, a válasz típusát. A JSON<->Java mappelést a JAX-RS automatikusan el fogja végezni.
 
 
===Request és Response megadása===
Nézzünk egy példát ahol a kliens meghívja a POST:login interfészt, a request body JSON stukturáját a LoginRequest objektum írja le, a választ pedig a LoginResponse.
<source lang="java">
public class LoginResponse {
private String user;
private String pass;
//getters and setters ...
}
 
public class LoginResponse {
private String userId;
private String token;
//getters and setters ...
}
</source>
 
Ekkor a request így fog kinézni:
<pre>
$ curl -XPOST 'localhost:8080/rest/login?' -H 'Content-Type: application/json' -d'
{ "user":"adam", "pass":"1234" }
</pre>
 
 
<source lang="java">
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
 
 
private static Client client = ClientBuilder.newClient();
 
LoginRequst loginRequest = new LoginRequest();
 
LoginResponse loginResponse = client.target(baseUrl).path("login").
request(MediaType.APPLICATION_JSON).post(Entity.json(loginRequest), LoginResponse.class);
</source>
 
A válaszban az alábbi JSON fog visszaérkezni:
<pre>
{ "userId":"11111", "token":"XXXXXX"}
</pre>
Amit a JAX-RS mappelni fog egy LoginResponse objektumba.
 
 
===Templét használata a request-ben===
A request URL-ben használhatunk PATH és request paramétereket is, amikhez a JAX-RS kliens behelyettesítő metódusokat biztosít. A PAHT paramétereket a resolveTemplate() metódussal, míg a QUERY paramétereket a queryParam() metódussal helyettesíthetjük be:
<source lang="java">
 
WebTarget target = client.target("http://commerce.com/customers/{id}")
.resolveTemplate("id", "123")
.queryParam("verbose", true);
 
</source>
 
 
===Listák kezelése a válaszban===
Ha az interfész válaszában egy POJO listát kapunk vissza, akkor a válasz típusának a megadását az alábbiak szerint kell megadni: ű
<source lang="java">
Client client = ClientBuilder.newClient();
List<Book> books = client.target(url)
.request(MediaType.APPLICATION_JSON).get(new GenericType<List<Book>>(){});
</source>
 
==Hibakezelés==
 
A hibák kezelésére három megközelítést fogunk alkalmazni, amik egybevágnak a server implementációnál tárgyalt megközelítésekkel.
# Exception kezelés: A get(), put(), post().. metódusoknál továbbra is megadjuk a válasz objektum típusát. 200 -as válasz esetében a JAX-RS automatikusan mappelni fogja a választ a megadott objektumba, így ha nem volt hiba, egy Java objektumban megkapjuk a választ. Ha bármilyen hiba dobódik az interfész hívása közben, akkor a JAX-RS kivétel típusából tudhatjuk, hogy milyen hiba történt. A kivételből ki tudjuk szedni a válasz body-ban esetlegesen küldött objektumot.
# A get(), post().. HTTP metódusokban nem mondjuk meg a válasz típusát. Ekkor a kliens a HTTP státusztól függetlenül egy '''javax.ws.rs.core.Response''' objektummal fog visszatérni ha volt hiba hanem. Ekkor a Response-ból nekünk kell kiszedni a válasz objektumot a '''readEntity(Class<T> entityType)''' metódussal és a HTTP státuszt a '''getStatus()''' metódussal.
# A harmadik megközelítés egy változata a másodiknak. Ahelyett, hogy a readEntity() hívással a JAX-RS -e bíznánk a parszolást, a JSON/XML String reprezentációját kérjük el a válaszból, és azt manuálisan parszoljuk.
 
 
===Exception kezelés===
https://dennis-xlc.gitbooks.io/restful-java-with-jax-rs-2-0-en/cn/part1/chapter7/exception_handling.html<br>
Talán ez a legtisztább megközelítés, megadjuk a HTTP metódusban a válasz objektum típusát, amit sikeres futás esetén (HTTP 200) meg fogunk kapni a megadott JAVA objektumban out-of-the-box.
 
 
<source lang="java">
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;
 
private static Client client = ClientBuilder.newClient();
 
LoginRequst loginRequest = new LoginRequest();
try {
LoginRequst loginRequest = client.target(baseUrl).path("login").
request(MediaType.APPLICATION_JSON).post(Entity.json(loginRequest), LoginRequst.class);
 
// 400-as hibák
} catch (ClientErrorException e) {
 
ErrorMessageResponse errorMessageResponse = e.getResponse().readEntity(ErrorMessageResponse.class);
int status = e.getResponse().getStatus();
 
// 500-as hibák
} catch (ServerErrorException e) {
...
// 300-as redirekt hibák
} catch (RedirectionException e) {
...
}
</source>
 
 
 
{| class="wikitable"
! style="font-weight:bold; background-color:#c0c0c0;" | Base Exception
! style="font-weight:bold; background-color:#c0c0c0;" | Status code range
! style="font-weight:bold; background-color:#c0c0c0;" | Description
|-
| ClientErrorException
| 4XX
| Client side error
|-
| ServerErrorException
| 5XX
| Server side error
|-
| RedirectionException
| 3XX
| Redirect
|}
 
 
 
{| class="wikitable"
! style="font-weight:bold; background-color:#c0c0c0;" | Exception
! style="font-weight:bold; background-color:#c0c0c0;" | Status code
! style="font-weight:bold; background-color:#c0c0c0;" | Description
|-
| BadRequestException
| 400
| Malformed message
|-
| NotAuthorizedException
| 401
| Authentication failure
|-
| ForbiddenException
| 403
| Not permitted to access
|-
| NotFoundException
| 404
| Couldn’t find resource
|-
| NotAllowedException
| 405
| HTTP method not supported
|-
| NotAcceptableException
| 406
| Client media type requested not supported
|-
| NotSupportedException
| 415
| Client posted media type not supported
|-
| InternalServerErrorException
| 500
| General server error
|-
| ServiceUnavailableException
| 503
| Server is temporarily unavailable or busy
|}
 
===Response objektum használata===
 
<source lang="java">
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;
 
private static Client client = ClientBuilder.newClient();
 
 
LoginRequst loginRequest = new LoginRequest();
 
Response response = client.target(baseUrl).path("login").
request(MediaType.APPLICATION_JSON).post(Entity.json(loginRequest));
 
int status = e.getResponse().getStatus();
 
if (status < 300) {
LoginResponse loginResponse = response.readEntity(LoginResponse.class);
 
} else {
ErrorMessageResponse errorMessageResponse = response.readEntity(ErrorMessageResponse.class);
}
</source>
 
 
===Response as String===
 
<source lang="java">
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.8</version>
</dependency>
</source>
 
<source lang="java">
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;
 
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
 
private static Client client = ClientBuilder.newClient();
private static ObjectMapper objectMapper = new ObjectMapper();
 
LoginRequst loginRequest = new LoginRequest();
 
Response response = client.target(baseUrl).path("login").
request(MediaType.APPLICATION_JSON).post(Entity.json(loginRequest));
 
String responseString = response.readEntity(String.class);
int status = e.getResponse().getStatus();
 
LoginResponse loginResponse = objectMapper.readValue(responseString,LoginResponse.class);
</source>