【问题标题】:Spring MVC: Fallback for unknown language code in uri parameter valueSpring MVC:uri参数值中未知语言代码的后备
【发布时间】:2015-08-30 16:22:23
【问题描述】:

我正在尝试构建我的第一个支持 i18n 的 Spring MVC 4 应用程序,并且正在考虑如何使用默认/备用语言环境,以防用户将语言 uri 参数操作为不存在或受支持的语言环境 例如 http://localhost.de?lang=abc

我正在使用代码

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

如果我第一次打开网址,这通常有效,但它似乎不适用于我所描述的情况。 我知道有一种机制可以使用默认消息属性文件,但我想为这种情况设置默认/备用语言环境。 我是否需要实现自定义过滤器?

【问题讨论】:

  • 没人知道吗?搜索了很多,但还没有找到解决方案或想法......
  • 导航到localhost.de?lang=abc 时会发生什么?在这种情况下使用什么语言环境?
  • 我不能再告诉你了,因为我已经构建了一个检查语言代码的过滤器。如果我的应用程序不支持这种语言,我会手动将其设置为我的默认语言。因此,在您的情况下,它将设置为“de”/ German...
  • 如果您愿意,您可以发布您的过滤器代码作为答案。看到它对我和其他人会有帮助。

标签: java spring spring-mvc internationalization


【解决方案1】:

一个很晚的答案,但我认为在 spring mvc 中设置默认语言环境的最简单方法是使用您的默认语言设置 i18n 文件属性。

例如,如果您的应用程序中有两种语言可用(假设英语和德语),那么您有以下文件:

messages_de.properties
messages_en.properties

然后你可以简单地将messages_de.properties复制到messages.properties,那么你就:

messages_de.properties
messages_en.properties
messages.properties

lang 参数与应用程序中可用的任何 i18n 文件不匹配时,Spring mvc 将自动回退到 messages.properties 文件。

【讨论】:

    【解决方案2】:

    我的建议是继承 SessionLocaleResolver 并覆盖 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;
            }
        }
    }
    

    这不会以任何主要方式修改 Spring 类,并且在可预见的将来可能会毫无问题地工作。

    【讨论】:

      【解决方案3】:

      可能远非完美,但这是我构建的......

      我还需要说,由于 SEO 的需要,我稍微更改了默认语言选择机制,我决定不使用 get 参数,而是使用所选语言的 uri 路径的第一部分来更改语言。 例如: http://myurl.com/en/test.html 而不是 http://myurl.com/test.html?lang=de

      在我的基于注释的配置中:

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

      语言环境解析器

      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;
          }
      
      }
      

      检查 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;
          }
      
      }
      

      }

      在我的情况下,前端路径是“资源”,其中所有静态文件(如 js、css、字体等)都在放置。 localizationService.getSupportedLocaleLanguageIsoCodes() 是一个包含当前三种语言代码(en、ru、de)的 Set。 因此,如果出现错误的语言代码,例如 abc,我会使用我的默认语言“de”进行转发。对我来说,这是/是可以接受的解决方案,因为 uri 中有错误的语言代码意味着 uri 是由用户操纵的......

      就像我说的那样,它可能不是“解决方案”;例如,我不确定它如何以及是否与 cookie 和/或“记住我”身份验证(使用 spring 安全性)一起工作......只是没有时间测试它......

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-11-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-27
        • 2018-12-16
        • 1970-01-01
        相关资源
        最近更新 更多