2009-12-08 4 views
10

Primavera Versione: 2.5.6Spring MVC: Risolvere la vista sulla base di User-Agent

voglio risolvere la vista in un file di velocità specifica in base al valore dell'intestazione User-Agent.

La mia linea di pensiero corrente è un'implementazione simile a UrlBasedViewResolver tale che il valore di user-agent è Map'd (tramite contesto) a una directory specifica (valore) basata su una corrispondenza di un'espressione regolare (chiave).

Sono quasi certo che esiste un modo più semplice.

Una domanda simile era stata precedentemente pubblicata sulla determinazione del tema basata su User-Agent. Tuttavia, la mia comprensione è che i temi si riferiscono più al contenuto statico (css, js), non al file che gestisce la costruzione della risposta effettiva (HTML, XML, ecc.).

+1

Un risolutore di viste personalizzato sarebbe abbastanza semplice, non credo che diventerai più semplice di così. – skaffman

+0

Sì, solo per assicurarmi che non stia trascurando qualcosa di ovvio. –

risposta

1

Vado con un resolver di visualizzazione personalizzato come suggerito nei commenti. (e aggiornando la mia app alla Spring 3.0.0)

+3

UPDATE: Spring 3.0 fornisce una soluzione pronta all'uso che utilizza il nuovo ContentNegotiatingViewResolver. –

1

Un'alternativa che non richiede la configurazione in un ViewResolver potrebbe coinvolgere un file Velocity di livello superiore, quindi analizzare in modo subordinato i file secondari con qualcosa di simile al seguente.

#if ($userAgent1) 
    #parse ("user-agent-1.vm") 
#elseif ($userAgent2) 
    #parse ("user-agent-2.vm") 
#end 

Tuttavia, l'implementazione di un nuovo o estensione di un ViewResolver esistente è una soluzione molto semplice e sarebbe il modo mi piacerebbe andare con.

+0

Funzionerebbe se 1) non fosse letteralmente decine di migliaia di agenti utente là fuori 2) l'agente utente non potrebbe essere falsificato. In generale, se vuoi rilevare l'agente utente, probabilmente stai già facendo qualcosa di sbagliato. – Esko

+0

@Esko "probabilmente sta già facendo qualcosa di sbagliato"? Ci sono molti requisiti là fuori, e non tutti coinvolgono tutti i diecimila user-agent. –

+1

Occasionalmente devi fare sacrifici per far funzionare le cose con determinati browser. * cough * Internet Explorer * cough * –

2

Ho avuto lo stesso problema qualche mese fa!

Sul nostro progetto mobile (utilizzando Spring 2.5.6) abbiamo finito per utilizzare un intercettore con il nostro SimpleUrlHandler. Ciò ha catturato tutte le richieste in arrivo e aggiunto -m.jsp alla fine di qualsiasi mobile richieste.

ha coinvolto due fasi:

1) che dichiara un intercettore al nostro Mapper URL di serie:

<bean id="handlerMapping" 
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 
<!-- This interceptor catches all 
requests and redirects them to portal 
or mobile html content. 
--> 
<property name="interceptors"> <list> 
     <ref bean="MultiViewController"/> </list> </property> 

e 2) l'attuazione della Interceptor, che sembrava per la parola 'mobile' nel dall'utente agente.

public class MultiViewController extends HandlerInterceptorAdapter { 

ne parlo più in dettaglio sul mio blog (circa il nuovo mondo emozionante di sviluppo web mobile) posta: http://plumnash.com/it/iphone-web-development-using-spring/

2

C'è un altra opzione suggerita here

Tuttavia ho deciso Estendendo a ContentNegotiatingViewResolver e sovrascrivendo il metodo resolveViewName, ho chiamato il mio ViewResolver HttpHeaderParamViewResolver. Il metodo esteso simile a questa:

@Override 
public View resolveViewName(String viewName, Locale locale) throws Exception { 
    //Get the HTTP Header param "User-Agent" 
    String headerParamValue = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getHeader(headerParam); 

    viewName = setViewName(viewName, headerParamValue); 

    return super.resolveViewName(viewName, locale); 
} 

Dove headerParam = "User-Agent" (o qualsiasi altro parametro HTTP Header vi piace, questo è definito nel xml di fagioli), dopo di che si valuta e determinare il viewName. Nel mio caso, il HttpHeaderParamViewResolver può essere configurato con una mappa in cui la chiave è un prefisso da aggiungere all'effettivo viewName e il valore è un RegExp che verrà utilizzato per valutare il valore dell'intestazione param.Sembra qualcosa di simile nel contesto XML App:

<bean id="HttpHeaderViewResolver" class="com.application.viewresolver.HttpHeaderParamViewResolver"> 
    <property name="viewResolvers"> 
     <list> 
      <ref bean="tilesViewResolver"/> 
     </list> 
    </property> 
    <property name="headerParam" value="User-Agent"/> 
    <property name="viewPrefixPattern"> 
     <map> 
      <entry> 
       <key> 
        <value>mobile-webkit</value> 
       </key> 
       <value>iPhone.*Apple.*Mobile.*Safari</value> 
      </entry> 
      <entry> 
       <key> 
        <value>mobile-bb</value> 
       </key> 
       <value>BlackBerry([0-9]{0,4})([a-zA-Z])?</value> 
      </entry> 
     </map> 
    </property> 
</bean> 

In questo modo il mio controller se chiama una vista chiamato UserDetails e accede l'applicazione con un iPhone il primo modello cattura i essa e aggiunge il Mobile- webkit suffisso quindi la vista è ora mobile-webkit-userDettagli e passa quindi a tilesViewResolver che genera la vista effettiva.

Ho esplorato molte possibilità e penso che questo sia il modo più semplice e flessibile che sono riuscito a trovare. In questo caso, la possibilità di scegliere una visione completamente diversa è stata fondamentale perché supportiamo un'ampia varietà di agenti utente, da WAP a IPhone 4 e dispositivi mobili compatibili con WebKit, pertanto le visualizzazioni cambiano notevolmente da user-agent a user-agent. Un altro vantaggio è che non è più necessario gestire questo problema sulla vista poiché è possibile avere visualizzazioni specializzate a piacere. Un altro lato positivo è che è possibile implementarlo abbastanza facilmente senza dover rimuovere o modificare i risolutori di visualizzazione che si potrebbero avere dal ContentNegotiatingViewResolver ha la capacità di delegare la chiamata di visualizzazione ad altri resolver di vista nella sequenza specifica definita.

Il lato negativo è che potresti essere tentato di specializzarti troppo nelle viste e finire con un sacco di file di visualizzazione che rendono l'app un incubo sostenibile.

spero che sia utile.

+1

Funziona solo su Spring 3.0 poiché non c'è ContentNegotiatingViewResolver nelle versioni precedenti – Chepech