Registrazione di richieste e risposte in un unico posto con JAX-RS

Ho un server web RESTEasy con molti metodi. Voglio implementare il logback per tenere traccia di tutte le richieste e le risposte, ma non voglio aggiungere log.info() a tutti i metodi.

Forse c’è modo di raccogliere richieste e risposte in un unico posto e registrarlo. Forse qualcosa come un filtro sulla catena del processo di richiesta HTTP su RESTEasy.

 @Path("/rest") @Produces("application/json") public class CounterRestService { //Don't want use log in controler every method to track requests and responces static final Logger log = LoggerFactory.getLogger(CounterRestService.class); @POST @Path("/create") public CounterResponce create(@QueryParam("name") String name) { log.info("create "+name) try { CounterService.getInstance().put(name); log.info("responce data"); // <- :(( return new CounterResponce(); } catch (Exception e){ log.info("responce error data"); // <- :(( return new CounterResponce("error", e.getMessage()); } } @POST @Path("/insert") public CounterResponce create(Counter counter) { try { CounterService.getInstance().put(counter); return new CounterResponce(); } catch (Exception e){ return new CounterResponce("error", e.getMessage()); } } ... } 

È ansible creare filtri e collegarli facilmente agli endpoint che è necessario registrare, mantenendo gli endpoint snelli e focalizzati sulla logica di business.

Definizione di un’annotazione di binding del nome

Per associare i filtri ai tuoi endpoint REST, JAX-RS fornisce la meta-annotazione @NameBinding e può essere utilizzata come segue:

 @NameBinding @Retention(RUNTIME) @Target({TYPE, METHOD}) public @interface Logged { } 

Registrazione della richiesta HTTP

L’annotazione @Logged verrà utilizzata per decorare una class filtro, che implementa ContainerRequestFilter , consentendo di gestire la richiesta:

 @Logged @Provider public class RequestLoggingFilter implements ContainerRequestFilter { @Override public void filter(ContainerRequestContext requestContext) throws IOException { // Use the ContainerRequestContext to extract information from the HTTP request // Information such as the URI, headers and HTTP entity are available } } 

L’annotazione @Provider indica un’implementazione di un’interfaccia di estensione che dovrebbe essere rilevabile dal runtime JAX-RS durante una fase di scansione del provider.

ContainerRequestContext ti aiuta a estrarre informazioni dalla richiesta HTTP.

Ecco i metodi dell’API ContainerRequestContext per ottenere informazioni dalla richiesta HTTP che può essere utile per i tuoi registri:

  • ContainerRequestContext#getMethod() : ContainerRequestContext#getMethod() il metodo HTTP dalla richiesta.
  • ContainerRequestContext#getUriInfo() : ottiene informazioni URI dalla richiesta HTTP.
  • ContainerRequestContext#getHeaders() : ottiene le intestazioni dalla richiesta HTTP.
  • ContainerRequestContext#getMediaType() : ottiene il tipo di media dell’ quadro.
  • ContainerRequestContext#getEntityStream() : ottiene il stream di input dell’ quadro.

Registrazione della risposta HTTP

Per registrare la risposta, prendere in considerazione l’implementazione di ContainerResponseFilter :

 @Logged @Provider public class ResponseLoggingFilter implements ContainerResponseFilter { @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { // Use the ContainerRequestContext to extract information from the HTTP request // Use the ContainerResponseContext to extract information from the HTTP response } } 

ContainerResponseContext ti aiuta a estrarre informazioni dalla risposta HTTP.

Ecco alcuni metodi dall’API ContainerResponseContext per ottenere informazioni dalla risposta HTTP che possono essere utili per i tuoi registri:

  • ContainerResponseContext#getStatus() : ottiene il codice di stato dalla risposta HTTP.
  • ContainerResponseContext#getHeaders() : ottiene le intestazioni dalla risposta HTTP.
  • ContainerResponseContext#getEntityStream() : ottiene il stream di output dell’entity framework.

Associazione dei filtri agli endpoint

Per associare il filtro ai metodi o alle classi degli endpoint, @Logged con l’annotazione @Logged definita sopra. Per i metodi e / o le classi annotati, i filtri verranno eseguiti:

 @Path("/") public class MyEndpoint { @GET @Path("{id}") @Produces("application/json") public Response myMethod(@PathParam("id") Long id) { // This method is not annotated with @Logged // The logging filters won't be executed when invoking this method ... } @DELETE @Logged @Path("{id}") @Produces("application/json") public Response myLoggedMethod(@PathParam("id") Long id) { // This method is annotated with @Logged // The request logging filter will be executed before invoking this method // The response logging filter will be executed before invoking this method ... } } 

Nell’esempio sopra, i filtri di registrazione verranno eseguiti solo per myLoggedMethod(Long) perché è annotato con @Logged .

Informazioni aggiuntive

Oltre ai metodi disponibili nelle interfacce ContainerRequestContext e ContainerResponseFilter , puoi inserire ResourceInfo nei filtri usando @Context :

 @Context ResourceInfo resourceInfo; 

Può essere usato per ottenere il Method e la Class che corrispondono all’URL richiesto:

 Class resourceClass = resourceInfo.getResourceClass(); Method resourceMethod = resourceInfo.getResourceMethod(); 

HttpServletRequest e HttpServletResponse sono anche disponibili per l’iniezione:

 @Context HttpServletRequest httpServletRequest; @Context HttpServletResponse httpServletResponse; 

Fare riferimento a questa risposta per i tipi che possono essere iniettati con @Context .

Prova gli Interceptor (non solo gli intercettori EJB alla vaniglia, puoi usare CDI con quello).

Sono lì per implementare Cross Cutting Concerns (aspetti).