2015-06-15 3 views
10

Sto cercando di creare la mia prima app MVC 4 di primavera con supporto i18n e stavo pensando a come utilizzare un locale predefinito/fallback nel caso in cui l'utente stia manipolando il linguaggio uri parametro da un locale non esistente o supportato per esempio http://localhost.de?lang=abcSpring MVC: fallback per codice lingua sconosciuta nel valore del parametro uri

Im utilizzando il codice

@Bean 
public LocaleResolver localeResolver() { 
    SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver(); 
    sessionLocaleResolver.setDefaultLocale(Locale.GERMAN); 
    return sessionLocaleResolver; 
} 

che funziona in generale se apro l'url la prima volta, ma sembra di non lavorare per il caso stavo descrivendo. So che esiste un meccanismo che userebbe il file delle proprietà dei messaggi predefinito, ma vorrei impostare un locale predefinito/fallback per questo caso. Devo forse implementare un filtro personalizzato?

+0

Nessuno ha un'idea? Cercavo molto ma non riuscivo a trovare ancora una soluzione o un'idea .... – StephanM

+0

Cosa succede quando navighi su http://localhost.de?lang=abc? Quale locale è usato in questo caso? –

+0

Non posso dirti più come ho già costruito un filtro che controlla il codice della lingua. Se la mia app non supporta questo linguaggio, lo imposto manualmente nella mia lingua predefinita. Quindi nel tuo caso sarebbe impostato su "de"/tedesco ... – StephanM

risposta

5

Probabilmente lungi dall'essere perfetto, ma questo è quello che ho costruito ...

Ho anche bisogno di dire che ho cambiato il meccanismo di selezione lingua di default un po 'a causa di SEO ha bisogno e ho deciso di cambiare la lingua non da utilizzando un parametro get ma utilizzando invece la prima parte del mio percorso uri per la lingua selezionata. Per esempio: http://myurl.com/en/test.html invece di http://myurl.com/test.html?lang=de

Nella mia configurazione base della nota:

@Bean 
public LocaleResolver localeResolver() { 
    UriLocaleResolver uriLocaleResolver = new UriLocaleResolver(); 
    return uriLocaleResolver; 
} 

Il locale resolver

public class UriLocaleResolver implements LocaleResolver { 

    private final Logger logger = LoggerFactory.getLogger(getClass()); 

    private Locale locale = null; 

    @Autowired 
    private LocalizationService localizationService; 


    @Override 
    public Locale resolveLocale(final HttpServletRequest servletRequest) { 
     if (locale != null) { 
      return locale; 
     } 

     String languageIsoCode = null; 
     try { 
      languageIsoCode = ((String)servletRequest.getAttribute(RequestKey.LANGUAGE_ISO_CODE)).toLowerCase(); 
     } 
     catch (Exception e) { } 
     if (StringUtils.isBlank(languageIsoCode) || !localizationService.getSupportedLocaleLanguageIsoCodes().contains(languageIsoCode)) { 
      logger.trace("Couldn't find valid language iso code. Using default locale '{}'", GlobalConstant.DEFAULT_LOCALE); 
      return GlobalConstant.DEFAULT_LOCALE; 
     } 

     logger.trace("Found language iso code '{}'", languageIsoCode); 
     return new Locale(languageIsoCode); 
    } 

    @Override 
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale)  { 
    this.locale = locale; 
    } 

} 

Il filtro che verifica la presenza di un codice lingua valido l'URI ..

@Component 
public class UriLocalizationFilter extends OncePerRequestFilter { 

    private final Logger logger = LoggerFactory.getLogger(getClass()); 

    @Autowired 
    private LocalizationService localizationService; 


    @Override 
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 
     String uri = request.getRequestURI().substring(request.getContextPath().length()); 
     String[] pathParts = uri.split("/"); 

     if (!uri.startsWith(GlobalConstant.FRONTEND_RESOURCE_PATH_PREFIX) && pathParts.length >= 1 && pathParts[1].length() == 2) { 
      String originalLanguageIsoCode = pathParts[1]; 
      String lowerCaseLanguageIsoCode = originalLanguageIsoCode.toLowerCase(); 

      if (localizationService.getSupportedLocaleLanguageIsoCodes().contains(lowerCaseLanguageIsoCode)) { 
       logger.debug("Found valid language iso code {}", lowerCaseLanguageIsoCode); 
      } 
      else { 
       logger.debug("Found invalid language iso code {}. Using default language iso code {}.", lowerCaseLanguageIsoCode, GlobalConstant.DEFAULT_LOCALE.getLanguage()); 
       lowerCaseLanguageIsoCode = GlobalConstant.DEFAULT_LOCALE.getLanguage(); 
      } 

      String newUrl = StringUtils.removeStart(uri, '/' + originalLanguageIsoCode); 
      request.setAttribute(RequestKey.LANGUAGE_ISO_CODE, lowerCaseLanguageIsoCode); 
      logger.debug("Dispatching to new url '{}'", newUrl); 
      request.getRequestDispatcher(newUrl).forward(request, response); 
     } 
     else { 
      filterChain.doFilter(request, response); 
     } 
    } 

    public void setLocalizationService(LocalizationService localizationService) { 
     this.localizationService = localizationService; 
    } 

} 

}

Il percorso di frontend è "risorse" nel mio caso in cui sono in posa tutti i file statici come js, css, fonts ecc. localizationService.getSupportedLocaleLanguageIsoCodes() è un Set contenente attualmente tre codici lingua (en, ru, de). Quindi in caso di un codice lingua errato come abc im facendo un forward con la mia lingua predefinita "de". Per me è stato/è una soluzione accettabile perché avere un codice lingua errato in uri significa che l'uri è stato manipolato dall'utente ...

Come ho detto la sua forse non "la" soluzione; per esempio non sono sicuro di come e se funziona con i cookie e/o l'autenticazione "ricordami" (usando la sicurezza di primavera) ... non avevo ancora il tempo di provarlo ...

7

Il mio suggerimento sarebbe di sottoclassi SessionLocaleResolver e l'override del metodo getLocale:

@SpringBootApplication 
public class DemoApplication { 

    public static void main(String[] args) { 
     SpringApplication.run(DemoApplication.class, args); 
    } 

    private static Set<Locale> allowedLocales; 

    static { 
     HashSet<Locale> allowed = new HashSet<>(); 
     allowed.add(Locale.GERMAN); 
     allowed.add(Locale.CANADA); 
     allowedLocales = Collections.unmodifiableSet(allowed); 

    } 

    @Bean 
    LocaleResolver localeResolver() { 
     return new LimitedSessionLocaleResolver(); 
    } 

    class LimitedSessionLocaleResolver extends SessionLocaleResolver { 
     @Override 
     public Locale resolveLocale(HttpServletRequest request) { 
      Locale locale = super.resolveLocale(request); 
      if (!allowedLocales.contains(locale)) { 
       return determineDefaultLocale(request); 
      } 
      return locale; 
     } 
    } 
} 

Questo non modifica le classi primavera in alcun modo importante ed è destinata probabilmente a lavorare senza problemi per il prossimo futuro.

Problemi correlati