Spring MVC:uri参数值中未知语言代码的回退

Ste*_*anM 10 java spring spring-mvc internationalization

我试图构建我的第一个支持i18n的Spring MVC 4应用程序,并且正在思考如何在用户将语言uri参数操作到非现有或支持的语言环境时如何使用默认/回退语言环境例如 http:// localhost .DE?LANG = ABC

我正在使用代码

@Bean
public LocaleResolver localeResolver() {
    SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
    sessionLocaleResolver.setDefaultLocale(Locale.GERMAN);
    return sessionLocaleResolver;
}
Run Code Online (Sandbox Code Playgroud)

一般情况下,如果我第一次打开网址,但它似乎不适用于我描述的情况.我知道有一种机制可以使用默认的消息属性文件,但我想为这种情况设置一个默认/回退区域设置.我是否需要实现自定义过滤器?

小智 7

我的建议是继承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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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


Ste*_*anM 5

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

我还需要说,由于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;
}
Run Code Online (Sandbox Code Playgroud)

区域解析器

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

}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

}

在我的情况下,前端路径是"资源",其中所有静态文件如js,css,fonts等正在铺设.localizationService.getSupportedLocaleLanguageIsoCodes()是一个包含当前三种语言代码(en,ru,de)的Set.因此,如果使用错误的语言代码,例如使用我的默认语言"de"进行转发.对我来说这是/是可接受的解决方案因为在uri中有错误的语言代码意味着uri被用户操纵...

就像我说它可能不是"解决方案"; 例如,我不知道如何以及它是如何工作与cookie和/或"记住我"认证(使用弹簧安全)...只是没有时间测试它...