gpt4 book ai didi

url - 语言环境作为 Spring MVC 中 URL 的一部分

转载 作者:行者123 更新时间:2023-12-03 20:43:49 26 4
gpt4 key购买 nike

我现在正在寻找多语言网络应用程序的框架。目前在我看来,最好的选择是 Spring MVC。但我面临这样一个事实,即所有开发人员指南都建议以这种方式使用 LocaleChangeInterceptor 切换语言:

http://www.somesite.com/action/?locale=en

不幸的是,我想避免这种情况有很多原因。如何使语言代码成为 URL 的重要组成部分?例如:

http://www.somesite.com/en/action

谢谢。

更新:我找到了以下解决方案。它还没有完成,但是可以工作。解决方案由两部分组成 - servlet 过滤器和语言环境解析器 bean。它看起来有点骇人听闻,但我看不到解决此问题的其他方法。

public class LocaleFilter implements Filter
{

...

private static final String DEFAULT_LOCALE = "en";
private static final String[] AVAILABLE_LOCALES = new String[] {"en", "ru"};

public LocaleFilter() {}

private List<String> getSevletRequestParts(ServletRequest request)
{
String[] splitedParts = ((HttpServletRequest) request).getServletPath().split("/");
List<String> result = new ArrayList<String>();

for (String sp : splitedParts)
{
if (sp.trim().length() > 0)
result.add(sp);
}

return result;
}

private Locale getLocaleFromRequestParts(List<String> parts)
{
if (parts.size() > 0)
{
for (String lang : AVAILABLE_LOCALES)
{
if (lang.equals(parts.get(0)))
{
return new Locale(lang);
}
}
}

return null;
}

@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
{
List<String> requestParts = this.getSevletRequestParts(request);
Locale locale = this.getLocaleFromRequestParts(requestParts);

if (locale != null)
{
request.setAttribute(LocaleFilter.class.getName() + ".LOCALE", locale);

StringBuilder sb = new StringBuilder();
for (int i = 1; i < requestParts.size(); i++)
{
sb.append('/');
sb.append((String) requestParts.get(i));
}

RequestDispatcher dispatcher = request.getRequestDispatcher(sb.toString());
dispatcher.forward(request, response);
}
else
{
request.setAttribute(LocaleFilter.class.getName() + ".LOCALE", new Locale(DEFAULT_LOCALE));
chain.doFilter(request, response);
}
}

...
}

public class FilterLocaleResolver implements LocaleResolver
{

private Locale DEFAULT_LOCALE = new Locale("en");

@Override
public Locale resolveLocale(HttpServletRequest request)
{
Locale locale = (Locale) request.getAttribute(LocaleFilter.class.getName() + ".LOCALE");
return (locale != null ? locale : DEFAULT_LOCALE);
}

@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale)
{
request.setAttribute(LocaleFilter.class.getName() + ".LOCALE", locale);
}

}

因此,无需在 Controller 的每个操作中映射语言环境。以下示例将正常工作:
@Controller
@RequestMapping("/test")
public class TestController
{

@RequestMapping("action")
public ModelAndView action(HttpServletRequest request, HttpServletResponse response)
{
ModelAndView mav = new ModelAndView("test/action");
...
return mav;
}

}

最佳答案

我使用过滤器和拦截器的组合实现了一些非常相似的东西。

过滤器提取第一个路径变量,如果它是有效的语言环境,则将其设置为请求属性,将其从请求的 URI 的开头剥离并将请求转发到新的 URI。

public class PathVariableLocaleFilter extends OncePerRequestFilter {
private static final Logger LOG = LoggerFactory.getLogger(PathVariableLocaleFilter.class);

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

if (variables.length > 1 && isLocale(variables[1])) {
LOG.debug("Found locale {}", variables[1]);
request.setAttribute(LOCALE_ATTRIBUTE_NAME, variables[1]);
String newUrl = StringUtils.removeStart(url, '/' + variables[1]);
LOG.trace("Dispatching to new url \'{}\'", newUrl);
RequestDispatcher dispatcher = request.getRequestDispatcher(newUrl);
dispatcher.forward(request, response);
} else {
filterChain.doFilter(request, response);
}
}

private boolean isLocale(String locale) {
//validate the string here against an accepted list of locales or whatever
try {
LocaleUtils.toLocale(locale);
return true;
} catch (IllegalArgumentException e) {
LOG.trace("Variable \'{}\' is not a Locale", locale);
}
return false;
}
}

拦截器与 LocaleChangeInterceptor 非常相似,它会尝试从请求属性中获取语言环境,如果找到了语言环境,它会将其设置为 LocaleResolver .
public class LocaleAttributeChangeInterceptor extends HandlerInterceptorAdapter {
public static final String LOCALE_ATTRIBUTE_NAME = LocaleAttributeChangeInterceptor.class.getName() + ".LOCALE";

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

Object newLocale = request.getAttribute(LOCALE_ATTRIBUTE_NAME);
if (newLocale != null) {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
if (localeResolver == null) {
throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");
}
localeResolver.setLocale(request, response, StringUtils.parseLocaleString(newLocale.toString()));
}
// Proceed in any case.
return true;
}
}

一旦你有了它们,你需要配置 Spring 以使用拦截器和 LocaleResolver .
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleAttributeChangeInterceptor());
}

@Bean(name = "localeResolver")
public LocaleResolver getLocaleResolver() {
return new CookieLocaleResolver();
}

并将过滤器添加到 AbstractAnnotationConfigDispatcherServletInitializer .
@Override
protected Filter[] getServletFilters() {
return new Filter[] { new PathVariableLocaleFilter() };
}

我还没有彻底测试它,但它似乎到目前为止工作,你不必触摸你的 Controller 来接受 {locale}路径变量,它应该开箱即用。也许在 future 我们会有'语言环境作为路径变量/子文件夹' Spring automagic 解决方案,因为似乎越来越多的网站正在采用它,并且根据一些它是 the way to go .

关于url - 语言环境作为 Spring MVC 中 URL 的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3221632/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com