2013-09-30 8 views
7

Sto costruendo un semplice servizio web AJAX/JSON con Spring. Il flusso di dati comune è:Convalida DTO di primavera in servizio o controller?

some DTO from browser 

      v 

Spring @Controller method 

      v 

    Spring @Service method 

sto cercando il modo più semplice per gestire la convalida dei dati.

  • Conosco l'annotazione @Valid che funziona piuttosto bene nei metodi @Controller.
  • Perché il @Validnon funziona con i metodi @Service?

Intendo: un metodo di servizio può essere utilizzato da qualsiasi altro servizio e controller. Quindi non avrebbe molto più senso convalidare a livello @Service?


Prendiamo questo semplice esempio:

MyDTO.java:

public class MyDTO { 
    @NotNull 
    public String required 
    @Min(18) 
    public int age; 
} 

MyServiceImpl.java:

public MyDomainObject foo(MyDTO myDTO) { 
    // persist myDTO 
    // and return created domain object 
} 

MyController.java:

@Autowired 
MyService myService; 

@Autowired  // some simple bean mapper like Dozer or Orika 
Mapper mapper; // for converting domain objects to DTO 

@RequestMapping(...) 
public MyDomainObjectDTO doSomething(@RequestBody MyDTO myDTO) { 
    mapper.map(myService.foo(myDTO), MyDomainObjectDTO.class); 
} 

È prassi comune che il metodo di servizio riceva il DTO?

  • Se yes: qual è la procedura migliore per convalidare tale DTO all'interno del metodo di servizio?
  • Se no: Forse il controller può manipolare l'oggetto Dominio e lasciare che il servizio salvi quell'oggetto? (questo mi sembra abbastanza inutile)

A mio parere il servizio dovrebbe essere responsabile della sola coerenza dei dati.

Come si risolve?

+0

possibile duplicato di [Verifica precondizioni nel livello Controller o Servizio] (http://stackoverflow.com/questions/11929781/check-preconditions-in-controller-or-service-layer) –

risposta

10

La mia risposta? Entrambi.

Il servizio deve verificare il proprio contratto per validità.

Il controller fa parte dell'interfaccia utente. Dovrebbe convalidare e associare per un'esperienza utente migliore, ma il servizio non dovrebbe fare affidamento su di esso.

Il servizio non può sapere come viene chiamato. Cosa succede se lo avvolgi come servizio REST?

Il servizio conosce anche le violazioni della logica aziendale in un modo che nessuna interfaccia utente può. È necessario convalidare per assicurarsi che il caso d'uso sia soddisfatto in modo appropriato.

Doppia borsa; Fai entrambi.

+0

Ma allora perché il servizio non funziona t consentire le annotazioni '@ Valid'? ... Ho capito il tuo punto, il servizio e il controller possono usare (per esempio) diversi campi nelle loro classi. Nella mia app, è sempre la stessa. Per questo motivo, passo al DTO attraverso il DTO. –

+0

Perché c'è una differenza tra la validazione e la programmazione difensiva/gestione degli errori. Detto questo, io uso la validazione per la programmazione difensiva. Pubblicherò presto una risposta. –

2

vedere la mia altra risposta: Check preconditions in Controller or Service layer

Se si vuole veramente fare la convalida come la gestione degli errori nel vostro livello di servizio simile a Spring MVC è possibile utilizzare javax.validation e AspectJ (a consiglio i metodi per convalidare), che è quello che ho fare perché mi piace fare riflessioni sul lavoro e sulla programmazione dichiarativa (annotazioni).

Spring MVC non deve eseguire AspectJ/AOP per eseguire la gestione degli errori poiché i metodi vengono richiamati tramite reflection (instradamento/invio URL).

Infine per voi il codice MVC si deve sapere che è una sorta di @Valid non ufficialmente deprecato. Invece considerare @Validated che farà leva più delle caratteristiche javax.validation.

+0

Io uso '@ Validated' a livello di servizio, che è abbastanza impressionante. Basta registrarsi 'MethodValidationPostProcessor' di primavera, poi mettere un' @ Validated' annotazione sull'interfaccia Servizio stesso e, ultimo ma non meno importante mettere un po '@ Valid' o' @ notnull' annotazioni sulle firme dei metodi definiti nell'interfaccia servizio. ServiceImpl rimane pulito. Funziona molto bene! L'unico "problema" è che il 'propertyPath' all'interno della gettata' ConstraintViolationException' ottenere preceduto la gerarchia di richiamo intero, vale a dire 'controllerMethod.serviceMethod.dtoProperty'. Devo in qualche modo liberarmi di questo. –

+0

Che cosa si intende per 'una sorta di non ufficialmente deprecata'? – prettyvoid