Spring LocalResolver是否基于查询参数“ lang = en”?

时间:2018-08-15 14:38:53

标签: java spring spring-mvc spring-boot

我可以告诉spring-boot通过查询参数(例如locale)自动解析请求的&lang=en吗?

我想赋予查询参数优先于Accept-Language参数。

我发现了以下两个属性,但与查询参数无关。

spring.mvc.locale= # Locale to use. By default, this locale is overridden by the "Accept-Language" header.
spring.mvc.locale-resolver=accept-header # Define how the locale should be resolved.

我尝试如下,但有一个例外:

@Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
   @Bean
   public LocaleChangeInterceptor localeChangeInterceptor() {
       LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
       lci.setParamName("lang");
       return lci;
   }

   @Override
   public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(localeChangeInterceptor());
   }
}

结果:

java.lang.UnsupportedOperationException: Cannot change HTTP accept header - use a different locale resolution strategy

2 个答案:

答案 0 :(得分:1)

首先,让我们看看会发生什么:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.UnsupportedOperationException: Cannot change HTTP accept header - use a different locale resolution strategy
...
Caused by: java.lang.UnsupportedOperationException: Cannot change HTTP accept header - use a different locale resolution strategy
    at org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver.setLocale(AcceptHeaderLocaleResolver.java:142) ~[spring-webmvc-5.3.2.jar:5.3.2]
    at org.springframework.web.servlet.i18n.LocaleChangeInterceptor.preHandle(LocaleChangeInterceptor.java:154) ~[spring-webmvc-5.3.2.jar:5.3.2]
...

调试后你就会知道:

  1. accept-header 不支持 preHandle,您不能使用 LocaleChangeInterceptor
  2. accept-header 没有任何支持的语言,您必须手动添加它们。你可以看到这个issue

accept-header 仅在您设置支持的语言并且语言与客户端浏览器中的 Content-Language 匹配时才有效。

因此,您无需使用 spring.mvc.locale-resolverspring.web.locale-resolver 。现在spring 5.3.2,不需要任何属性。

您的示例解决此问题的方法是附加另一个 LocaleResolverspring.io

    @Bean
    public LocaleResolver localeResolver() {
        return new SessionLocaleResolver();//new CookieLocaleResolver();
    }

并设置:

spring:
  main:
    allow-bean-definition-overriding: true # SpringBoot>=2.1.0 
  web:
    locale: en # default

答案 1 :(得分:0)

解决方法可能如下。我仍然觉得该设置非常违反直觉。尤其是我曾期望:

  • LocaleChangeInterceptor会自行注册,但不会注册,必须显式调用addInterceptors()
  • spring.mvc.locale参数仍设置在自定义LocaleResolver中,但没有设置,必须从WebMvcProperties手动覆盖

如果所有这些都需要,文档可能需要对此进行更多解释。

@Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
   @Bean
   public LocaleChangeInterceptor localeChangeInterceptor() {
       LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
       lci.setParamName("lang");
       return lci;
   }

   @Override
   public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(localeChangeInterceptor());
   }

   @Bean
   public AcceptHeaderLocaleResolver localeResolver(WebMvcProperties mvcProperties) {
        AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver() {
            @Override
            public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
                LocaleContextHolder.setLocale(locale);
            }
        };

        localeResolver.setDefaultLocale(mvcProperties.getLocale());
        return localeResolver;
    }
}

讨论后更新改进的版本:

@Configuration
public class AppConfig implements WebMvcConfigurer {
   @Bean
   public AcceptHeaderLocaleResolver localeResolver(WebMvcProperties mvcProperties) {
        AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver() {
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            String locale = request.getParameter("lang");
            return locale != null
                    ? org.springframework.util.StringUtils.parseLocaleString(locale)
                    : super.resolveLocale(request);
        }
        };

        localeResolver.setDefaultLocale(mvcProperties.getLocale());
        return localeResolver;
    }
}