2012-06-27 20 views
6

In un'applicazione Web che utilizza Spring Data JPA con Hibernate, utilizziamo la funzionalità web pagination per fornire funzionalità di impaginazione e ordinamento in vari elenchi di entità.Dati Spring JPA Parametri page.sort non validi

@Controller 
public class MyEntityController { 
    @RequestMapping(method = RequestMethod.GET) 
    public ModelAndView list(Pageable pageable) { ... } 
} 

@Configuration 
public class MyWebMvcConfig extends WebMvcConfigurationSupport { 
    @Override 
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { 
     super.addArgumentResolvers(argumentResolvers); 
     argumentResolvers.add(new PageableArgumentResolver()); 
    } 
} 

public interface MyEntityRepository extends PagingAndSortingRepository<MyEntity, String> { 
    Page<MyEntity> findByPropertyX(String propertyX, Pageable pagable); 
} 

Questo permette oggetti di entità da definire in html reso come speciale sorta request parameters, dove il valore page.sort corrisponde in effetti una proprietà nell'entità su cui ordinare.

<table> 
    <thead> 
     <tr> 
      <th><a href="?page.sort=propertyX&amp;page.sort.dir=asc">Property X</a></th> 
      <th><a href="?page.sort=propertyY&amp;page.sort.dir=asc">Property Y</a></th> 
     </tr> 
    </thead> 
    <tbody>...</tbody> 
</table> 

Questo produce un URL risultante come ad esempio:

http://host/context-root/entities/?page.sort=propertyX&page.sort.dir=asc 

Il problema è che gli utenti possono modificare l'URL da utilizzare valida page.sort proprietà che sia di riferimento i nomi di colonna/di proprietà inesistenti o, peggio, che utilizza caratteri di query JPA non validi che producono una sintassi non valida.

Ad esempio, se l'URL viene modificato per ordinare su "noSuchProperty":

http://host/context-root/entities/?page.sort=noSuchProperty&page.sort.dir=asc 

ma questa proprietà non esiste, saranno gettati la seguente eccezione:

java.lang.IllegalArgumentException: No property noSuchProperty found for type class com.my.company.MyEntity 
    at org.springframework.data.repository.query.parser.Property.<init>(Property.java:76) 
    . . . 
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:86) 
    . . . 
    at $Proxy68.findByPropertyX(Unknown Source) 
    at com.my.company.MyEntityRepository.findByPropertyX(MyEntityRepository.java:17 

Allo stesso modo, se l'URL viene modificato per un carattere sintassi di query non valida, ad esempio "" ":

http://host/context-root/entities/?page.sort=%22&page.sort.dir=asc 

il seguente err o si verificherà:

java.lang.StackOverflowError 
    java.util.regex.Pattern$GroupTail.match(Pattern.java:4227) 
    . . . 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 

(C'è anche un terzo sapore di eccezioni che si traduce in un org.hibernate.QueryException quando il @Query è definito esplicitamente sul metodo Repository.)

primavera dati JPA astrae i dettagli della ordinamento, impaginazione e gestione di questi parametri; tuttavia, non sembra gestire con grazia questi scenari (vale a dire dove viene specificato un parametro di ordinamento non valido).

È possibile aggiungere alcune regole personalizzate aggiuntive per convalidare che la proprietà di ordinamento esista effettivamente nell'entità; tuttavia, mi chiedo se ci sia un approccio più pulito e centralizzato per fare ciò in modo tale da non perdere i vantaggi e la semplicità delle astrazioni JPA di Spring Data. Utilizziamo questa capacità di ordinamento in tutta la nostra app con molte entità diverse, quindi idealmente, vorremmo più di un approccio generico, piuttosto che dover definire o controllare esplicitamente le proprietà di ordinamento per ogni pagina di entità richiesta. In particolare, estendiamo effettivamente il PageableArgumentResolver per accettare un valore predefinito di ordinamento annotato fornito nel nostro controller (non illustrato negli esempi di codice per semplicità), quindi ci piacerebbe solo ricorrere a questo ordinamento predefinito, o solo l'ordine di ordinamento predefinito per l'entità, piuttosto che generare un'eccezione.

Alcune idee e tentativi .. Potrei usare un QueryCreationListener per intercettare la creazione della query e ottenere il parametro sort; tuttavia, non posso realmente modificare la query a quel punto. Oppure, posso estendere e utilizzare un custom PageableArgumentResolver (lo stiamo già facendo) per ottenere i parametri di ordinamento; tuttavia, non ho accesso all'entità a quel punto, né la capacità di determinare se l'entità abbia effettivamente una proprietà con quel nome.Potremmo dichiarare esplicitamente le proprietà supportate; tuttavia, ancora una volta, questo sconfigge l'idea di gestire centralmente e automaticamente questo scenario senza richiedere una conoscenza specifica o dichiarata delle entità.

Esiste un altro tipo di intercettore o costrutto simile che possa utilizzare per convalidare centralmente i parametri di ordinamento pageable e modificare se necessario prima di richiamare la query? O c'è qualche tipo di configurazione o modo in cui Spring può gestire automaticamente questo scenario in modo tale che gestisca più correttamente i parametri di ordinamento non validi?

risposta

3

Stavo dando un'occhiata al codice e penso che qualche altra traccia dello stack sarebbe stata utile. Ma da quello che posso vedere, penso che ci sono due posti che potresti voler affrontare se sei in vena di riscrivere un codice Spring.

Qui ci sono due scenari, nel primo si passa un campo di ordinamento che non esiste nell'oggetto/tabella. Quello che vuoi veramente è che quel parametro cattivo venga ignorato silenziosamente tutto il tempo, non solo quando passi in un 1 PageableArgumentResolver] 1. Sto pensando che dovrebbe essere un'opzione su AbstractQueryCreator (e quindi su JpaQueryCreator) per ignorare i parametri non validi su un ordinamento.

La seconda parte da affrontare è probabilmente lo PageableArgumentResolver. Se passi stringhe vuote o qualcosa che non ha senso come %20 allora dovrebbe ignorare quel parametro e non inviarlo allo PageRequest.

Happy hacking e buona fortuna. Leggere il tuo post mi ha fatto capire che il mio sito è vulnerabile allo stesso problema e in realtà non ho una buona soluzione.

1

Penso che il miglioramento del PageableArgumentResolver gestisca con grazia questi scenari. Potrebbe provare a creare un'istanza PropertyPath da String consegnata come Sort e assicurarsi quindi che sia valida. Sono un po 'lacerato dal fatto che abbia senso semplicemente abbandonare l'invalido String per impostazione predefinita, il che restituirebbe il risultato non ordinato. Questa è probabilmente l'esperienza più semplice, ma potrebbe anche portare a noiosi tentativi di scoprire perché il risultato non è ordinato.

Tuttavia, esso. Sarebbe bello se potessi ottenere un biglietto JIRA per questo contro Spring Data Commons e collegare questo biglietto qui. Sentiti libero di aprire una richiesta di ritiro nel caso in cui hai messo a punto un'implementazione praticabile. Grazie per averlo già portato in tavola!