Comprehensive update to the framework's TimeZone handling, including a new TimeZoneAwareLocaleContext and a LocaleContextResolver for Spring MVC
A few noteworthy minor changes: LocaleContext.getLocale() may return null in special cases (not by default), which our own accessing classes are able to handle now. If there is a non-null TimeZone user setting, we're exposing it to all collaborating libraries, in particular to JSTL, Velocity and JasperReports. Our JSR-310 and Joda-Time support falls back to checking the general LocaleContext TimeZone now, adapting it to their time zone types, if no more specific setting has been provided. Our DefaultConversionService has TimeZone<->ZoneId converters registered. And finally, we're using a custom parseTimeZoneString method now that doesn't accept the TimeZone.getTimeZone(String) GMT fallback for an invalid time zone id anymore. Issue: SPR-1528
This commit is contained in:
@@ -28,7 +28,6 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -36,6 +35,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
@@ -1042,16 +1042,17 @@ public class DispatcherServlet extends FrameworkServlet {
|
||||
*/
|
||||
@Override
|
||||
protected LocaleContext buildLocaleContext(final HttpServletRequest request) {
|
||||
return new LocaleContext() {
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return localeResolver.resolveLocale(request);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return getLocale().toString();
|
||||
}
|
||||
};
|
||||
if (this.localeResolver instanceof LocaleContextResolver) {
|
||||
return ((LocaleContextResolver) this.localeResolver).resolveLocaleContext(request);
|
||||
}
|
||||
else {
|
||||
return new LocaleContext() {
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return localeResolver.resolveLocale(request);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.servlet;
|
||||
|
||||
import java.util.Locale;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContext;
|
||||
|
||||
/**
|
||||
* Extension of {@link LocaleResolver}, adding support for a rich locale context
|
||||
* (potentially including locale and time zone information).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @see org.springframework.context.i18n.LocaleContext
|
||||
* @see org.springframework.context.i18n.TimeZoneAwareLocaleContext
|
||||
* @see org.springframework.context.i18n.LocaleContextHolder
|
||||
* @see org.springframework.web.servlet.support.RequestContext#getTimeZone
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getTimeZone
|
||||
*/
|
||||
public interface LocaleContextResolver extends LocaleResolver {
|
||||
|
||||
/**
|
||||
* Resolve the current locale context via the given request.
|
||||
* <p>This is primarily intended for framework-level processing; consider using
|
||||
* {@link org.springframework.web.servlet.support.RequestContextUtils} or
|
||||
* {@link org.springframework.web.servlet.support.RequestContext} for
|
||||
* application-level access to the current locale and/or time zone.
|
||||
* <p>The returned context may be a
|
||||
* {@link org.springframework.context.i18n.TimeZoneAwareLocaleContext},
|
||||
* containing a locale with associated time zone information.
|
||||
* Simply apply an {@code instanceof} check and downcast accordingly.
|
||||
* <p>Custom resolver implementations may also return extra settings in
|
||||
* the returned context, which again can be accessed through downcasting.
|
||||
* @param request the request to resolve the locale context for
|
||||
* @return the current locale context (never {@code null}
|
||||
* @see #resolveLocale(HttpServletRequest)
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getTimeZone
|
||||
*/
|
||||
LocaleContext resolveLocaleContext(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Set the current locale context to the given one,
|
||||
* potentially including a locale with associated time zone information.
|
||||
* @param request the request to be used for locale modification
|
||||
* @param response the response to be used for locale modification
|
||||
* @param localeContext the new locale context, or {@code null} to clear the locale
|
||||
* @throws UnsupportedOperationException if the LocaleResolver implementation
|
||||
* does not support dynamic changing of the locale or time zone
|
||||
* @see #setLocale(HttpServletRequest, HttpServletResponse, Locale)
|
||||
* @see org.springframework.context.i18n.SimpleLocaleContext
|
||||
* @see org.springframework.context.i18n.SimpleTimeZoneAwareLocaleContext
|
||||
*/
|
||||
void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext);
|
||||
|
||||
}
|
||||
@@ -34,8 +34,19 @@ import javax.servlet.http.HttpServletResponse;
|
||||
* to retrieve the current locale in controllers or views, independent
|
||||
* of the actual resolution strategy.
|
||||
*
|
||||
* <p>Note: As of Spring 4.0, there is an extended strategy interface
|
||||
* called {@link LocaleContextResolver}, allowing for resolution of
|
||||
* a {@link org.springframework.context.i18n.LocaleContext} object,
|
||||
* potentially including associated time zone information. Spring's
|
||||
* provided resolver implementations implement the extended
|
||||
* {@link LocaleContextResolver} interface wherever appropriate.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 27.02.2003
|
||||
* @see LocaleContextResolver
|
||||
* @see org.springframework.context.i18n.LocaleContextHolder
|
||||
* @see org.springframework.web.servlet.support.RequestContext#getLocale
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
|
||||
*/
|
||||
public interface LocaleResolver {
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.servlet.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.i18n.SimpleLocaleContext;
|
||||
import org.springframework.web.servlet.LocaleContextResolver;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link LocaleContextResolver} implementations.
|
||||
* Provides support for a default locale and a default time zone.
|
||||
*
|
||||
* <p>Also provides pre-implemented versions of {@link #resolveLocale} and {@link #setLocale},
|
||||
* delegating to {@link #resolveLocaleContext} and {@link #setLocaleContext}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @see #setDefaultLocale
|
||||
* @see #setDefaultTimeZone
|
||||
*/
|
||||
public abstract class AbstractLocaleContextResolver extends AbstractLocaleResolver implements LocaleContextResolver {
|
||||
|
||||
private TimeZone defaultTimeZone;
|
||||
|
||||
|
||||
/**
|
||||
* Set a default TimeZone that this resolver will return if no other time zone found.
|
||||
*/
|
||||
public void setDefaultTimeZone(TimeZone defaultTimeZone) {
|
||||
this.defaultTimeZone = defaultTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default TimeZone that this resolver is supposed to fall back to, if any.
|
||||
*/
|
||||
public TimeZone getDefaultTimeZone() {
|
||||
return this.defaultTimeZone;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Locale resolveLocale(HttpServletRequest request) {
|
||||
return resolveLocaleContext(request).getLocale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
|
||||
setLocaleContext(request, response, (locale != null ? new SimpleLocaleContext(locale) : null));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,6 +26,7 @@ import org.springframework.web.servlet.LocaleResolver;
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2.9
|
||||
* @see #setDefaultLocale
|
||||
*/
|
||||
public abstract class AbstractLocaleResolver implements LocaleResolver {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,12 +17,16 @@
|
||||
package org.springframework.web.servlet.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContext;
|
||||
import org.springframework.context.i18n.SimpleLocaleContext;
|
||||
import org.springframework.context.i18n.TimeZoneAwareLocaleContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.LocaleContextResolver;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.util.CookieGenerator;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
@@ -33,29 +37,44 @@ import org.springframework.web.util.WebUtils;
|
||||
* or the request's accept-header locale.
|
||||
*
|
||||
* <p>This is particularly useful for stateless applications without user sessions.
|
||||
* The cookie may optionally contain an associated time zone value as well;
|
||||
* alternatively, you may specify a default time zone.
|
||||
*
|
||||
* <p>Custom controllers can thus override the user's locale by calling
|
||||
* {@link #setLocale(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.util.Locale)},
|
||||
* for example responding to a certain locale change request.
|
||||
* <p>Custom controllers can override the user's locale and time zone by calling
|
||||
* {@code #setLocale(Context)} on the resolver, e.g. responding to a locale change
|
||||
* request. As a more convenient alternative, consider using
|
||||
* {@link org.springframework.web.servlet.support.RequestContext#changeLocale}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Jean-Pierre Pawlak
|
||||
* @since 27.02.2003
|
||||
* @see #setDefaultLocale
|
||||
* @see #setLocale
|
||||
* @see #setDefaultTimeZone
|
||||
*/
|
||||
public class CookieLocaleResolver extends CookieGenerator implements LocaleResolver {
|
||||
public class CookieLocaleResolver extends CookieGenerator implements LocaleContextResolver {
|
||||
|
||||
/**
|
||||
* The name of the request attribute that holds the locale.
|
||||
* The name of the request attribute that holds the Locale.
|
||||
* <p>Only used for overriding a cookie value if the locale has been
|
||||
* changed in the course of the current request! Use
|
||||
* {@link org.springframework.web.servlet.support.RequestContext#getLocale}
|
||||
* changed in the course of the current request!
|
||||
* <p>Use {@code RequestContext(Utils).getLocale()}
|
||||
* to retrieve the current locale in controllers or views.
|
||||
* @see org.springframework.web.servlet.support.RequestContext#getLocale
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
|
||||
*/
|
||||
public static final String LOCALE_REQUEST_ATTRIBUTE_NAME = CookieLocaleResolver.class.getName() + ".LOCALE";
|
||||
|
||||
/**
|
||||
* The name of the request attribute that holds the TimeZone.
|
||||
* <p>Only used for overriding a cookie value if the locale has been
|
||||
* changed in the course of the current request!
|
||||
* <p>Use {@code RequestContext(Utils).getTimeZone()}
|
||||
* to retrieve the current time zone in controllers or views.
|
||||
* @see org.springframework.web.servlet.support.RequestContext#getTimeZone
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getTimeZone
|
||||
*/
|
||||
public static final String TIME_ZONE_REQUEST_ATTRIBUTE_NAME = CookieLocaleResolver.class.getName() + ".TIME_ZONE";
|
||||
|
||||
/**
|
||||
* The default cookie name used if none is explicitly set.
|
||||
*/
|
||||
@@ -64,9 +83,11 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleResol
|
||||
|
||||
private Locale defaultLocale;
|
||||
|
||||
private TimeZone defaultTimeZone;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link CookieLocaleResolver} class
|
||||
* Create a new instance of the {@link CookieLocaleResolver} class
|
||||
* using the {@link #DEFAULT_COOKIE_NAME default cookie name}.
|
||||
*/
|
||||
public CookieLocaleResolver() {
|
||||
@@ -88,45 +109,100 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleResol
|
||||
return this.defaultLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a fixed TimeZone that this resolver will return if no cookie found.
|
||||
*/
|
||||
public void setDefaultTimeZone(TimeZone defaultTimeZone) {
|
||||
this.defaultTimeZone = defaultTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fixed TimeZone that this resolver will return if no cookie found,
|
||||
* if any.
|
||||
*/
|
||||
protected TimeZone getDefaultTimeZone() {
|
||||
return this.defaultTimeZone;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Locale resolveLocale(HttpServletRequest request) {
|
||||
// Check request for pre-parsed or preset locale.
|
||||
Locale locale = (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
|
||||
if (locale != null) {
|
||||
return locale;
|
||||
}
|
||||
parseLocaleCookieIfNecessary(request);
|
||||
return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
|
||||
}
|
||||
|
||||
// Retrieve and parse cookie value.
|
||||
Cookie cookie = WebUtils.getCookie(request, getCookieName());
|
||||
if (cookie != null) {
|
||||
locale = StringUtils.parseLocaleString(cookie.getValue());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Parsed cookie value [" + cookie.getValue() + "] into locale '" + locale + "'");
|
||||
@Override
|
||||
public LocaleContext resolveLocaleContext(final HttpServletRequest request) {
|
||||
parseLocaleCookieIfNecessary(request);
|
||||
return new TimeZoneAwareLocaleContext() {
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
|
||||
}
|
||||
if (locale != null) {
|
||||
request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME, locale);
|
||||
return locale;
|
||||
@Override
|
||||
public TimeZone getTimeZone() {
|
||||
return (TimeZone) request.getAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return determineDefaultLocale(request);
|
||||
private void parseLocaleCookieIfNecessary(HttpServletRequest request) {
|
||||
if (request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME) == null) {
|
||||
// Retrieve and parse cookie value.
|
||||
Cookie cookie = WebUtils.getCookie(request, getCookieName());
|
||||
Locale locale = null;
|
||||
TimeZone timeZone = null;
|
||||
if (cookie != null) {
|
||||
String value = cookie.getValue();
|
||||
String localePart = value;
|
||||
String timeZonePart = null;
|
||||
int spaceIndex = localePart.indexOf(' ');
|
||||
if (spaceIndex != -1) {
|
||||
localePart = value.substring(0, spaceIndex);
|
||||
timeZonePart = value.substring(spaceIndex + 1);
|
||||
}
|
||||
locale = (!"-".equals(localePart) ? StringUtils.parseLocaleString(localePart) : null);
|
||||
if (timeZonePart != null) {
|
||||
timeZone = StringUtils.parseTimeZoneString(timeZonePart);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Parsed cookie value [" + cookie.getValue() + "] into locale '" + locale +
|
||||
"'" + (timeZone != null ? " and time zone '" + timeZone.getID() + "'" : ""));
|
||||
}
|
||||
}
|
||||
request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
|
||||
(locale != null ? locale: determineDefaultLocale(request)));
|
||||
request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
|
||||
(timeZone != null ? timeZone : determineDefaultTimeZone(request)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
|
||||
if (locale != null) {
|
||||
// Set request attribute and add cookie.
|
||||
request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME, locale);
|
||||
addCookie(response, locale.toString());
|
||||
setLocaleContext(request, response, (locale != null ? new SimpleLocaleContext(locale) : null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) {
|
||||
Locale locale = null;
|
||||
TimeZone timeZone = null;
|
||||
if (localeContext != null) {
|
||||
locale = localeContext.getLocale();
|
||||
if (localeContext instanceof TimeZoneAwareLocaleContext) {
|
||||
timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
|
||||
}
|
||||
addCookie(response, (locale != null ? locale : "-") + (timeZone != null ? ' ' + timeZone.getID() : ""));
|
||||
}
|
||||
else {
|
||||
// Set request attribute to fallback locale and remove cookie.
|
||||
request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME, determineDefaultLocale(request));
|
||||
removeCookie(response);
|
||||
}
|
||||
request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
|
||||
(locale != null ? locale: determineDefaultLocale(request)));
|
||||
request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
|
||||
(timeZone != null ? timeZone : determineDefaultTimeZone(request)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine the default locale for the given request,
|
||||
* Called if no locale cookie has been found.
|
||||
@@ -145,4 +221,17 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleResol
|
||||
return defaultLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the default time zone for the given request,
|
||||
* Called if no TimeZone cookie has been found.
|
||||
* <p>The default implementation returns the specified default time zone,
|
||||
* if any, or {@code null} otherwise.
|
||||
* @param request the request to resolve the time zone for
|
||||
* @return the default time zone (or {@code null} if none defined)
|
||||
* @see #setDefaultTimeZone
|
||||
*/
|
||||
protected TimeZone determineDefaultTimeZone(HttpServletRequest request) {
|
||||
return getDefaultTimeZone();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,30 +17,36 @@
|
||||
package org.springframework.web.servlet.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContext;
|
||||
import org.springframework.context.i18n.TimeZoneAwareLocaleContext;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.web.servlet.LocaleResolver} implementation
|
||||
* that always returns a fixed default locale. Default is the current
|
||||
* JVM's default locale.
|
||||
* that always returns a fixed default locale and optionally time zone.
|
||||
* Default is the current JVM's default locale.
|
||||
*
|
||||
* <p>Note: Does not support {@code setLocale}, as the fixed locale
|
||||
* cannot be changed.
|
||||
* <p>Note: Does not support {@code setLocale(Context)}, as the fixed
|
||||
* locale and time zone cannot be changed.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see #setDefaultLocale
|
||||
* @see #setDefaultTimeZone
|
||||
*/
|
||||
public class FixedLocaleResolver extends AbstractLocaleResolver {
|
||||
public class FixedLocaleResolver extends AbstractLocaleContextResolver {
|
||||
|
||||
/**
|
||||
* Create a default FixedLocaleResolver, exposing a configured default
|
||||
* locale (or the JVM's default locale as fallback).
|
||||
* @see #setDefaultLocale
|
||||
* @see #setDefaultTimeZone
|
||||
*/
|
||||
public FixedLocaleResolver() {
|
||||
setDefaultLocale(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,6 +57,16 @@ public class FixedLocaleResolver extends AbstractLocaleResolver {
|
||||
setDefaultLocale(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a FixedLocaleResolver that exposes the given locale and time zone.
|
||||
* @param locale the locale to expose
|
||||
* @param timeZone the time zone to expose
|
||||
*/
|
||||
public FixedLocaleResolver(Locale locale, TimeZone timeZone) {
|
||||
setDefaultLocale(locale);
|
||||
setDefaultTimeZone(timeZone);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Locale resolveLocale(HttpServletRequest request) {
|
||||
@@ -62,9 +78,22 @@ public class FixedLocaleResolver extends AbstractLocaleResolver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot change fixed locale - use a different locale resolution strategy");
|
||||
public LocaleContext resolveLocaleContext(HttpServletRequest request) {
|
||||
return new TimeZoneAwareLocaleContext() {
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return getDefaultLocale();
|
||||
}
|
||||
@Override
|
||||
public TimeZone getTimeZone() {
|
||||
return getDefaultTimeZone();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) {
|
||||
throw new UnsupportedOperationException("Cannot change fixed locale - use a different locale resolution strategy");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,10 +17,12 @@
|
||||
package org.springframework.web.servlet.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContext;
|
||||
import org.springframework.context.i18n.TimeZoneAwareLocaleContext;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
@@ -30,27 +32,41 @@ import org.springframework.web.util.WebUtils;
|
||||
*
|
||||
* <p>This is most appropriate if the application needs user sessions anyway,
|
||||
* that is, when the HttpSession does not have to be created for the locale.
|
||||
* The session may optionally contain an associated time zone attribute as well;
|
||||
* alternatively, you may specify a default time zone.
|
||||
*
|
||||
* <p>Custom controllers can override the user's locale by calling
|
||||
* {@code setLocale}, e.g. responding to a locale change request.
|
||||
* <p>Custom controllers can override the user's locale and time zone by calling
|
||||
* {@code #setLocale(Context)} on the resolver, e.g. responding to a locale change
|
||||
* request. As a more convenient alternative, consider using
|
||||
* {@link org.springframework.web.servlet.support.RequestContext#changeLocale}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 27.02.2003
|
||||
* @see #setDefaultLocale
|
||||
* @see #setLocale
|
||||
* @see #setDefaultTimeZone
|
||||
*/
|
||||
public class SessionLocaleResolver extends AbstractLocaleResolver {
|
||||
public class SessionLocaleResolver extends AbstractLocaleContextResolver {
|
||||
|
||||
/**
|
||||
* Name of the session attribute that holds the locale.
|
||||
* Name of the session attribute that holds the Locale.
|
||||
* Only used internally by this implementation.
|
||||
* Use {@code RequestContext(Utils).getLocale()}
|
||||
* <p>Use {@code RequestContext(Utils).getLocale()}
|
||||
* to retrieve the current locale in controllers or views.
|
||||
* @see org.springframework.web.servlet.support.RequestContext#getLocale
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
|
||||
*/
|
||||
public static final String LOCALE_SESSION_ATTRIBUTE_NAME = SessionLocaleResolver.class.getName() + ".LOCALE";
|
||||
|
||||
/**
|
||||
* Name of the session attribute that holds the TimeZone.
|
||||
* Only used internally by this implementation.
|
||||
* <p>Use {@code RequestContext(Utils).getTimeZone()}
|
||||
* to retrieve the current time zone in controllers or views.
|
||||
* @see org.springframework.web.servlet.support.RequestContext#getTimeZone
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getTimeZone
|
||||
*/
|
||||
public static final String TIME_ZONE_SESSION_ATTRIBUTE_NAME = SessionLocaleResolver.class.getName() + ".TIME_ZONE";
|
||||
|
||||
|
||||
@Override
|
||||
public Locale resolveLocale(HttpServletRequest request) {
|
||||
@@ -61,9 +77,46 @@ public class SessionLocaleResolver extends AbstractLocaleResolver {
|
||||
return locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocaleContext resolveLocaleContext(final HttpServletRequest request) {
|
||||
return new TimeZoneAwareLocaleContext() {
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
Locale locale = (Locale) WebUtils.getSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME);
|
||||
if (locale == null) {
|
||||
locale = determineDefaultLocale(request);
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
@Override
|
||||
public TimeZone getTimeZone() {
|
||||
TimeZone timeZone = (TimeZone) WebUtils.getSessionAttribute(request, TIME_ZONE_SESSION_ATTRIBUTE_NAME);
|
||||
if (timeZone == null) {
|
||||
timeZone = determineDefaultTimeZone(request);
|
||||
}
|
||||
return timeZone;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) {
|
||||
Locale locale = null;
|
||||
TimeZone timeZone = null;
|
||||
if (localeContext != null) {
|
||||
locale = localeContext.getLocale();
|
||||
if (localeContext instanceof TimeZoneAwareLocaleContext) {
|
||||
timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
|
||||
}
|
||||
}
|
||||
WebUtils.setSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME, locale);
|
||||
WebUtils.setSessionAttribute(request, TIME_ZONE_SESSION_ATTRIBUTE_NAME, timeZone);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine the default locale for the given request,
|
||||
* Called if no locale session attribute has been found.
|
||||
* Called if no Locale session attribute has been found.
|
||||
* <p>The default implementation returns the specified default locale,
|
||||
* if any, else falls back to the request's accept-header locale.
|
||||
* @param request the request to resolve the locale for
|
||||
@@ -79,9 +132,17 @@ public class SessionLocaleResolver extends AbstractLocaleResolver {
|
||||
return defaultLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
|
||||
WebUtils.setSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME, locale);
|
||||
/**
|
||||
* Determine the default time zone for the given request,
|
||||
* Called if no TimeZone session attribute has been found.
|
||||
* <p>The default implementation returns the specified default time zone,
|
||||
* if any, or {@code null} otherwise.
|
||||
* @param request the request to resolve the time zone for
|
||||
* @return the default time zone (or {@code null} if none defined)
|
||||
* @see #setDefaultTimeZone
|
||||
*/
|
||||
protected TimeZone determineDefaultTimeZone(HttpServletRequest request) {
|
||||
return getDefaultTimeZone();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,8 +21,9 @@ import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.Principal;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Locale;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
@@ -45,12 +46,15 @@ import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
* <li>{@link HttpSession}
|
||||
* <li>{@link Principal}
|
||||
* <li>{@link Locale}
|
||||
* <li>{@link TimeZone} (as of Spring 4.0)
|
||||
* <li>{@link java.time.ZoneId} (as of Spring 4.0 and Java 8)</li>
|
||||
* <li>{@link InputStream}
|
||||
* <li>{@link Reader}
|
||||
* </ul>
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ServletRequestMethodArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
@@ -64,6 +68,8 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
||||
HttpSession.class.isAssignableFrom(paramType) ||
|
||||
Principal.class.isAssignableFrom(paramType) ||
|
||||
Locale.class.equals(paramType) ||
|
||||
TimeZone.class.equals(paramType) ||
|
||||
"java.time.ZoneId".equals(paramType.getName()) ||
|
||||
InputStream.class.isAssignableFrom(paramType) ||
|
||||
Reader.class.isAssignableFrom(paramType);
|
||||
}
|
||||
@@ -97,6 +103,13 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
||||
else if (Locale.class.equals(paramType)) {
|
||||
return RequestContextUtils.getLocale(request);
|
||||
}
|
||||
else if (TimeZone.class.equals(paramType)) {
|
||||
TimeZone timeZone = RequestContextUtils.getTimeZone(request);
|
||||
return (timeZone != null ? timeZone : TimeZone.getDefault());
|
||||
}
|
||||
else if ("java.time.ZoneId".equals(paramType.getName())) {
|
||||
return ZoneIdResolver.resolveZoneId(request);
|
||||
}
|
||||
else if (InputStream.class.isAssignableFrom(paramType)) {
|
||||
return request.getInputStream();
|
||||
}
|
||||
@@ -110,4 +123,16 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid a hard-coded dependency on Java 8's {@link java.time.ZoneId}.
|
||||
*/
|
||||
private static class ZoneIdResolver {
|
||||
|
||||
public static Object resolveZoneId(HttpServletRequest request) {
|
||||
TimeZone timeZone = RequestContextUtils.getTimeZone(request);
|
||||
return (timeZone != null ? timeZone.toZoneId() : ZoneId.systemDefault());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.springframework.web.servlet.support;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
@@ -80,6 +80,10 @@ public abstract class JstlUtils {
|
||||
public static void exposeLocalizationContext(HttpServletRequest request, MessageSource messageSource) {
|
||||
Locale jstlLocale = RequestContextUtils.getLocale(request);
|
||||
Config.set(request, Config.FMT_LOCALE, jstlLocale);
|
||||
TimeZone timeZone = RequestContextUtils.getTimeZone(request);
|
||||
if (timeZone != null) {
|
||||
Config.set(request, Config.FMT_TIME_ZONE, timeZone);
|
||||
}
|
||||
if (messageSource != null) {
|
||||
LocalizationContext jstlContext = new SpringLocalizationContext(messageSource, request);
|
||||
Config.set(request, Config.FMT_LOCALIZATION_CONTEXT, jstlContext);
|
||||
@@ -95,6 +99,10 @@ public abstract class JstlUtils {
|
||||
*/
|
||||
public static void exposeLocalizationContext(RequestContext requestContext) {
|
||||
Config.set(requestContext.getRequest(), Config.FMT_LOCALE, requestContext.getLocale());
|
||||
TimeZone timeZone = requestContext.getTimeZone();
|
||||
if (timeZone != null) {
|
||||
Config.set(requestContext.getRequest(), Config.FMT_TIME_ZONE, timeZone);
|
||||
}
|
||||
MessageSource messageSource = getJstlAwareMessageSource(
|
||||
requestContext.getServletContext(), requestContext.getMessageSource());
|
||||
LocalizationContext jstlContext = new SpringLocalizationContext(messageSource, requestContext.getRequest());
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -29,6 +30,9 @@ import javax.servlet.jsp.jstl.core.Config;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.NoSuchMessageException;
|
||||
import org.springframework.context.i18n.LocaleContext;
|
||||
import org.springframework.context.i18n.SimpleTimeZoneAwareLocaleContext;
|
||||
import org.springframework.context.i18n.TimeZoneAwareLocaleContext;
|
||||
import org.springframework.ui.context.Theme;
|
||||
import org.springframework.ui.context.ThemeSource;
|
||||
import org.springframework.ui.context.support.ResourceBundleThemeSource;
|
||||
@@ -40,15 +44,17 @@ import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.EscapedErrors;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.LocaleContextResolver;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.ThemeResolver;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* Context holder for request-specific state, like current web application context, current locale, current theme, and
|
||||
* potential binding errors. Provides easy access to localized messages and Errors instances.
|
||||
* Context holder for request-specific state, like current web application context, current locale, current theme,
|
||||
* and potential binding errors. Provides easy access to localized messages and Errors instances.
|
||||
*
|
||||
* <p>Suitable for exposition to views, and usage within JSP's "useBean" tag, JSP scriptlets, JSTL EL, Velocity
|
||||
* templates, etc. Necessary for views that do not have access to the servlet request, like Velocity templates.
|
||||
@@ -56,8 +62,8 @@ import org.springframework.web.util.WebUtils;
|
||||
* <p>Can be instantiated manually, or automatically exposed to views as model attribute via AbstractView's
|
||||
* "requestContextAttribute" property.
|
||||
*
|
||||
* <p>Will also work outside of DispatcherServlet requests, accessing the root WebApplicationContext and using an
|
||||
* appropriate fallback for the locale (the HttpServletRequest's primary locale).
|
||||
* <p>Will also work outside of DispatcherServlet requests, accessing the root WebApplicationContext and using
|
||||
* an appropriate fallback for the locale (the HttpServletRequest's primary locale).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rossen Stoyanchev
|
||||
@@ -70,15 +76,16 @@ import org.springframework.web.util.WebUtils;
|
||||
public class RequestContext {
|
||||
|
||||
/**
|
||||
* Default theme name used if the RequestContext cannot find a ThemeResolver. Only applies to non-DispatcherServlet
|
||||
* requests. <p>Same as AbstractThemeResolver's default, but not linked in here to avoid package interdependencies.
|
||||
* Default theme name used if the RequestContext cannot find a ThemeResolver.
|
||||
* Only applies to non-DispatcherServlet requests.
|
||||
* <p>Same as AbstractThemeResolver's default, but not linked in here to avoid package interdependencies.
|
||||
* @see org.springframework.web.servlet.theme.AbstractThemeResolver#ORIGINAL_DEFAULT_THEME_NAME
|
||||
*/
|
||||
public static final String DEFAULT_THEME_NAME = "theme";
|
||||
|
||||
/**
|
||||
* Request attribute to hold the current web application context for RequestContext usage. By default, the
|
||||
* DispatcherServlet's context (or the root context as fallback) is exposed.
|
||||
* Request attribute to hold the current web application context for RequestContext usage.
|
||||
* By default, the DispatcherServlet's context (or the root context as fallback) is exposed.
|
||||
*/
|
||||
public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = RequestContext.class.getName() + ".CONTEXT";
|
||||
|
||||
@@ -102,6 +109,8 @@ public class RequestContext {
|
||||
|
||||
private Locale locale;
|
||||
|
||||
private TimeZone timeZone;
|
||||
|
||||
private Theme theme;
|
||||
|
||||
private Boolean defaultHtmlEscape;
|
||||
@@ -114,10 +123,11 @@ public class RequestContext {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new RequestContext for the given request, using the request attributes for Errors retrieval. <p>This
|
||||
* only works with InternalResourceViews, as Errors instances are part of the model and not normally exposed as
|
||||
* request attributes. It will typically be used within JSPs or custom tags. <p><b>Will only work within a
|
||||
* DispatcherServlet request.</b> Pass in a ServletContext to be able to fallback to the root WebApplicationContext.
|
||||
* Create a new RequestContext for the given request, using the request attributes for Errors retrieval.
|
||||
* <p>This only works with InternalResourceViews, as Errors instances are part of the model and not
|
||||
* normally exposed as request attributes. It will typically be used within JSPs or custom tags.
|
||||
* <p><b>Will only work within a DispatcherServlet request.</b>
|
||||
* Pass in a ServletContext to be able to fallback to the root WebApplicationContext.
|
||||
* @param request current HTTP request
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see #RequestContext(javax.servlet.http.HttpServletRequest, javax.servlet.ServletContext)
|
||||
@@ -127,13 +137,29 @@ public class RequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RequestContext for the given request, using the request attributes for Errors retrieval. <p>This
|
||||
* only works with InternalResourceViews, as Errors instances are part of the model and not normally exposed as
|
||||
* request attributes. It will typically be used within JSPs or custom tags. <p>If a ServletContext is specified,
|
||||
* the RequestContext will also work with the root WebApplicationContext (outside a DispatcherServlet).
|
||||
* Create a new RequestContext for the given request, using the request attributes for Errors retrieval.
|
||||
* <p>This only works with InternalResourceViews, as Errors instances are part of the model and not
|
||||
* normally exposed as request attributes. It will typically be used within JSPs or custom tags.
|
||||
* <p><b>Will only work within a DispatcherServlet request.</b>
|
||||
* Pass in a ServletContext to be able to fallback to the root WebApplicationContext.
|
||||
* @param request current HTTP request
|
||||
* @param servletContext the servlet context of the web application (can be {@code null}; necessary for
|
||||
* fallback to root WebApplicationContext)
|
||||
* @param response current HTTP response
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see #RequestContext(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.ServletContext, Map)
|
||||
*/
|
||||
public RequestContext(HttpServletRequest request, HttpServletResponse response) {
|
||||
initContext(request, response, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RequestContext for the given request, using the request attributes for Errors retrieval.
|
||||
* <p>This only works with InternalResourceViews, as Errors instances are part of the model and not
|
||||
* normally exposed as request attributes. It will typically be used within JSPs or custom tags.
|
||||
* <p>If a ServletContext is specified, the RequestContext will also work with the root
|
||||
* WebApplicationContext (outside a DispatcherServlet).
|
||||
* @param request current HTTP request
|
||||
* @param servletContext the servlet context of the web application (can be {@code null};
|
||||
* necessary for fallback to root WebApplicationContext)
|
||||
* @see org.springframework.web.context.WebApplicationContext
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
*/
|
||||
@@ -142,13 +168,13 @@ public class RequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RequestContext for the given request, using the given model attributes for Errors retrieval. <p>This
|
||||
* works with all View implementations. It will typically be used by View implementations. <p><b>Will only work
|
||||
* within a DispatcherServlet request.</b> Pass in a ServletContext to be able to fallback to the root
|
||||
* WebApplicationContext.
|
||||
* Create a new RequestContext for the given request, using the given model attributes for Errors retrieval.
|
||||
* <p>This works with all View implementations. It will typically be used by View implementations.
|
||||
* <p><b>Will only work within a DispatcherServlet request.</b>
|
||||
* Pass in a ServletContext to be able to fallback to the root WebApplicationContext.
|
||||
* @param request current HTTP request
|
||||
* @param model the model attributes for the current view (can be {@code null}, using the request attributes
|
||||
* for Errors retrieval)
|
||||
* @param model the model attributes for the current view (can be {@code null},
|
||||
* using the request attributes for Errors retrieval)
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see #RequestContext(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.ServletContext, Map)
|
||||
*/
|
||||
@@ -157,9 +183,10 @@ public class RequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RequestContext for the given request, using the given model attributes for Errors retrieval. <p>This
|
||||
* works with all View implementations. It will typically be used by View implementations. <p>If a ServletContext is
|
||||
* specified, the RequestContext will also work with a root WebApplicationContext (outside a DispatcherServlet).
|
||||
* Create a new RequestContext for the given request, using the given model attributes for Errors retrieval.
|
||||
* <p>This works with all View implementations. It will typically be used by View implementations.
|
||||
* <p>If a ServletContext is specified, the RequestContext will also work with a root
|
||||
* WebApplicationContext (outside a DispatcherServlet).
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param servletContext the servlet context of the web application (can be {@code null}; necessary for
|
||||
@@ -212,14 +239,25 @@ public class RequestContext {
|
||||
|
||||
// Determine locale to use for this RequestContext.
|
||||
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
|
||||
if (localeResolver != null) {
|
||||
if (localeResolver instanceof LocaleContextResolver) {
|
||||
LocaleContext localeContext = ((LocaleContextResolver) localeResolver).resolveLocaleContext(request);
|
||||
this.locale = localeContext.getLocale();
|
||||
if (localeContext instanceof TimeZoneAwareLocaleContext) {
|
||||
this.timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
|
||||
}
|
||||
}
|
||||
else if (localeResolver != null) {
|
||||
// Try LocaleResolver (we're within a DispatcherServlet request).
|
||||
this.locale = localeResolver.resolveLocale(request);
|
||||
}
|
||||
else {
|
||||
// No LocaleResolver available -> try fallback.
|
||||
|
||||
// Try JSTL fallbacks if necessary.
|
||||
if (this.locale == null) {
|
||||
this.locale = getFallbackLocale();
|
||||
}
|
||||
if (this.timeZone == null) {
|
||||
this.timeZone = getFallbackTimeZone();
|
||||
}
|
||||
|
||||
// Determine default HTML escape setting from the "defaultHtmlEscape"
|
||||
// context-param in web.xml, if any.
|
||||
@@ -235,9 +273,8 @@ public class RequestContext {
|
||||
|
||||
/**
|
||||
* Determine the fallback locale for this context.
|
||||
* <p>The default implementation checks for a JSTL locale attribute in request,
|
||||
* session or application scope; if not found, returns the
|
||||
* {@code HttpServletRequest.getLocale()}.
|
||||
* <p>The default implementation checks for a JSTL locale attribute in request, session
|
||||
* or application scope; if not found, returns the {@code HttpServletRequest.getLocale()}.
|
||||
* @return the fallback locale (never {@code null})
|
||||
* @see javax.servlet.http.HttpServletRequest#getLocale()
|
||||
*/
|
||||
@@ -251,6 +288,22 @@ public class RequestContext {
|
||||
return getRequest().getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the fallback time zone for this context.
|
||||
* <p>The default implementation checks for a JSTL time zone attribute in request,
|
||||
* session or application scope; returns {@code null} if not found.
|
||||
* @return the fallback time zone (or {@code null} if none derivable from the request)
|
||||
*/
|
||||
protected TimeZone getFallbackTimeZone() {
|
||||
if (jstlPresent) {
|
||||
TimeZone timeZone = JstlLocaleResolver.getJstlTimeZone(getRequest(), getServletContext());
|
||||
if (timeZone != null) {
|
||||
return timeZone;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the fallback theme for this context.
|
||||
* <p>The default implementation returns the default theme (with name "theme").
|
||||
@@ -306,17 +359,65 @@ public class RequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current Locale (never {@code null}).
|
||||
* Return the current Locale (falling back to the request locale; never {@code null}).
|
||||
* <p>Typically coming from a DispatcherServlet's {@link LocaleResolver}.
|
||||
* Also includes a fallback check for JSTL's Locale attribute.
|
||||
* @see RequestContextUtils#getLocale
|
||||
*/
|
||||
public final Locale getLocale() {
|
||||
return this.locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current TimeZone (or {@code null} if none derivable from the request).
|
||||
* <p>Typically coming from a DispatcherServlet's {@link LocaleContextResolver}.
|
||||
* Also includes a fallback check for JSTL's TimeZone attribute.
|
||||
* @see RequestContextUtils#getTimeZone
|
||||
*/
|
||||
public TimeZone getTimeZone() {
|
||||
return this.timeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the current locale to the specified one,
|
||||
* storing the new locale through the configured {@link LocaleResolver}.
|
||||
* @param locale the new locale
|
||||
* @see LocaleResolver#setLocale
|
||||
* @see #changeLocale(java.util.Locale, java.util.TimeZone)
|
||||
*/
|
||||
public void changeLocale(Locale locale) {
|
||||
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(this.request);
|
||||
if (localeResolver == null) {
|
||||
throw new IllegalStateException("Cannot change locale if no LocaleResolver configured");
|
||||
}
|
||||
localeResolver.setLocale(this.request, this.response, locale);
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the current locale to the specified locale and time zone context,
|
||||
* storing the new locale context through the configured {@link LocaleResolver}.
|
||||
* @param locale the new locale
|
||||
* @param timeZone the new time zone
|
||||
* @see LocaleContextResolver#setLocaleContext
|
||||
* @see org.springframework.context.i18n.SimpleTimeZoneAwareLocaleContext
|
||||
*/
|
||||
public void changeLocale(Locale locale, TimeZone timeZone) {
|
||||
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(this.request);
|
||||
if (!(localeResolver instanceof LocaleContextResolver)) {
|
||||
throw new IllegalStateException("Cannot change locale context if no LocaleContextResolver configured");
|
||||
}
|
||||
((LocaleContextResolver) localeResolver).setLocaleContext(this.request, this.response,
|
||||
new SimpleTimeZoneAwareLocaleContext(locale, timeZone));
|
||||
this.locale = locale;
|
||||
this.timeZone = timeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current theme (never {@code null}).
|
||||
* <p>Resolved lazily for more efficiency when theme support is not being used.
|
||||
*/
|
||||
public final Theme getTheme() {
|
||||
public Theme getTheme() {
|
||||
if (this.theme == null) {
|
||||
// Lazily determine theme to use for this RequestContext.
|
||||
this.theme = RequestContextUtils.getTheme(this.request);
|
||||
@@ -329,8 +430,39 @@ public class RequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* (De)activate default HTML escaping for messages and errors, for the scope of this RequestContext. The default is
|
||||
* the application-wide setting (the "defaultHtmlEscape" context-param in web.xml).
|
||||
* Change the current theme to the specified one,
|
||||
* storing the new theme name through the configured {@link ThemeResolver}.
|
||||
* @param theme the new theme
|
||||
* @see ThemeResolver#setThemeName
|
||||
*/
|
||||
public void changeTheme(Theme theme) {
|
||||
ThemeResolver themeResolver = RequestContextUtils.getThemeResolver(this.request);
|
||||
if (themeResolver == null) {
|
||||
throw new IllegalStateException("Cannot change theme if no ThemeResolver configured");
|
||||
}
|
||||
themeResolver.setThemeName(this.request, this.response, (theme != null ? theme.getName() : null));
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the current theme to the specified theme by name,
|
||||
* storing the new theme name through the configured {@link ThemeResolver}.
|
||||
* @param themeName the name of the new theme
|
||||
* @see ThemeResolver#setThemeName
|
||||
*/
|
||||
public void changeTheme(String themeName) {
|
||||
ThemeResolver themeResolver = RequestContextUtils.getThemeResolver(this.request);
|
||||
if (themeResolver == null) {
|
||||
throw new IllegalStateException("Cannot change theme if no ThemeResolver configured");
|
||||
}
|
||||
themeResolver.setThemeName(this.request, this.response, themeName);
|
||||
// Ask for re-resolution on next getTheme call.
|
||||
this.theme = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* (De)activate default HTML escaping for messages and errors, for the scope of this RequestContext.
|
||||
* <p>The default is the application-wide setting (the "defaultHtmlEscape" context-param in web.xml).
|
||||
* @see org.springframework.web.util.WebUtils#isDefaultHtmlEscape
|
||||
*/
|
||||
public void setDefaultHtmlEscape(boolean defaultHtmlEscape) {
|
||||
@@ -353,8 +485,8 @@ public class RequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the UrlPathHelper to use for context path and request URI decoding. Can be used to pass a shared
|
||||
* UrlPathHelper instance in.
|
||||
* Set the UrlPathHelper to use for context path and request URI decoding.
|
||||
* Can be used to pass a shared UrlPathHelper instance in.
|
||||
* <p>A default UrlPathHelper is always available.
|
||||
*/
|
||||
public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
|
||||
@@ -363,8 +495,8 @@ public class RequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the UrlPathHelper used for context path and request URI decoding. Can be used to configure the current
|
||||
* UrlPathHelper.
|
||||
* Return the UrlPathHelper used for context path and request URI decoding.
|
||||
* Can be used to configure the current UrlPathHelper.
|
||||
* <p>A default UrlPathHelper is always available.
|
||||
*/
|
||||
public UrlPathHelper getUrlPathHelper() {
|
||||
@@ -381,8 +513,9 @@ public class RequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the context path of the original request, that is, the path that indicates the current web application.
|
||||
* This is useful for building links to other resources within the application.
|
||||
* Return the context path of the original request, that is, the path that
|
||||
* indicates the current web application. This is useful for building links
|
||||
* to other resources within the application.
|
||||
* <p>Delegates to the UrlPathHelper for decoding.
|
||||
* @see javax.servlet.http.HttpServletRequest#getContextPath
|
||||
* @see #getUrlPathHelper
|
||||
@@ -408,7 +541,6 @@ public class RequestContext {
|
||||
* Return a context-aware URl for the given relative URL with placeholders (named keys with braces {@code {}}).
|
||||
* For example, send in a relative URL {@code foo/{bar}?spam={spam}} and a parameter map
|
||||
* {@code {bar=baz,spam=nuts}} and the result will be {@code [contextpath]/foo/baz?spam=nuts}.
|
||||
*
|
||||
* @param relativeUrl the relative URL part
|
||||
* @param params a map of parameters to insert as placeholders in the url
|
||||
* @return a URL that points back to the server with an absolute path (also URL-encoded accordingly)
|
||||
@@ -439,10 +571,9 @@ public class RequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the request URI of the original request, that is, the invoked URL without parameters. This is particularly
|
||||
* useful as HTML form action target, possibly in combination with the original query string. <p><b>Note this
|
||||
* implementation will correctly resolve to the URI of any originating root request in the presence of a forwarded
|
||||
* request. However, this can only work when the Servlet 2.4 'forward' request attributes are present.
|
||||
* Return the request URI of the original request, that is, the invoked URL
|
||||
* without parameters. This is particularly useful as HTML form action target,
|
||||
* possibly in combination with the original query string.
|
||||
* <p>Delegates to the UrlPathHelper for decoding.
|
||||
* @see #getQueryString
|
||||
* @see org.springframework.web.util.UrlPathHelper#getOriginatingRequestUri
|
||||
@@ -453,10 +584,9 @@ public class RequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query string of the current request, that is, the part after the request path. This is particularly
|
||||
* useful for building an HTML form action target in combination with the original request URI. <p><b>Note this
|
||||
* implementation will correctly resolve to the query string of any originating root request in the presence of a
|
||||
* forwarded request. However, this can only work when the Servlet 2.4 'forward' request attributes are present.
|
||||
* Return the query string of the current request, that is, the part after
|
||||
* the request path. This is particularly useful for building an HTML form
|
||||
* action target in combination with the original request URI.
|
||||
* <p>Delegates to the UrlPathHelper for decoding.
|
||||
* @see #getRequestUri
|
||||
* @see org.springframework.web.util.UrlPathHelper#getOriginatingQueryString
|
||||
@@ -768,6 +898,20 @@ public class RequestContext {
|
||||
}
|
||||
return (localeObject instanceof Locale ? (Locale) localeObject : null);
|
||||
}
|
||||
|
||||
public static TimeZone getJstlTimeZone(HttpServletRequest request, ServletContext servletContext) {
|
||||
Object timeZoneObject = Config.get(request, Config.FMT_TIME_ZONE);
|
||||
if (timeZoneObject == null) {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
timeZoneObject = Config.get(session, Config.FMT_TIME_ZONE);
|
||||
}
|
||||
if (timeZoneObject == null && servletContext != null) {
|
||||
timeZoneObject = Config.get(servletContext, Config.FMT_TIME_ZONE);
|
||||
}
|
||||
}
|
||||
return (timeZoneObject instanceof TimeZone ? (TimeZone) timeZoneObject : null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,11 +18,13 @@ package org.springframework.web.servlet.support;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContext;
|
||||
import org.springframework.context.i18n.TimeZoneAwareLocaleContext;
|
||||
import org.springframework.ui.context.Theme;
|
||||
import org.springframework.ui.context.ThemeSource;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
@@ -30,6 +32,7 @@ import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.FlashMap;
|
||||
import org.springframework.web.servlet.FlashMapManager;
|
||||
import org.springframework.web.servlet.LocaleContextResolver;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.ThemeResolver;
|
||||
|
||||
@@ -98,23 +101,51 @@ public abstract class RequestContextUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current locale from the given request,
|
||||
* using the LocaleResolver bound to the request by the DispatcherServlet
|
||||
* Retrieve the current locale from the given request, using the
|
||||
* LocaleResolver bound to the request by the DispatcherServlet
|
||||
* (if available), falling back to the request's accept-header Locale.
|
||||
* <p>This method serves as a straightforward alternative to the standard
|
||||
* Servlet {@link javax.servlet.http.HttpServletRequest#getLocale()} method,
|
||||
* falling back to the latter if no more specific locale has been found.
|
||||
* <p>Consider using {@link org.springframework.context.i18n.LocaleContextHolder#getLocale()}
|
||||
* which will normally be populated with the same Locale.
|
||||
* @param request current HTTP request
|
||||
* @return the current locale, either from the LocaleResolver or from
|
||||
* the plain request
|
||||
* @return the current locale for the given request, either from the
|
||||
* LocaleResolver or from the plain request itself
|
||||
* @see #getLocaleResolver
|
||||
* @see javax.servlet.http.HttpServletRequest#getLocale()
|
||||
* @see org.springframework.context.i18n.LocaleContextHolder#getLocale()
|
||||
*/
|
||||
public static Locale getLocale(HttpServletRequest request) {
|
||||
LocaleResolver localeResolver = getLocaleResolver(request);
|
||||
if (localeResolver != null) {
|
||||
return localeResolver.resolveLocale(request);
|
||||
}
|
||||
else {
|
||||
return request.getLocale();
|
||||
return (localeResolver != null ? localeResolver.resolveLocale(request) : request.getLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current time zone from the given request, using the
|
||||
* TimeZoneAwareLocaleResolver bound to the request by the DispatcherServlet
|
||||
* (if available), falling back to the system's default time zone.
|
||||
* <p>Note: This method returns {@code null} if no specific time zone can be
|
||||
* resolved for the given request. This is in contrast to {@link #getLocale}
|
||||
* where there is always the request's accept-header locale to fall back to.
|
||||
* <p>Consider using {@link org.springframework.context.i18n.LocaleContextHolder#getTimeZone()}
|
||||
* which will normally be populated with the same TimeZone: That method only
|
||||
* differs in terms of its fallback to the system time zone if the LocaleResolver
|
||||
* hasn't provided provided a specific time zone (instead of this method's {@code null}).
|
||||
* @param request current HTTP request
|
||||
* @return the current time zone for the given request, either from the
|
||||
* TimeZoneAwareLocaleResolver or {@code null} if none associated
|
||||
* @see #getLocaleResolver
|
||||
* @see org.springframework.context.i18n.LocaleContextHolder#getTimeZone()
|
||||
*/
|
||||
public static TimeZone getTimeZone(HttpServletRequest request) {
|
||||
LocaleResolver localeResolver = getLocaleResolver(request);
|
||||
if (localeResolver instanceof LocaleContextResolver) {
|
||||
LocaleContext localeContext = ((LocaleContextResolver) localeResolver).resolveLocaleContext(request);
|
||||
if (localeContext instanceof TimeZoneAwareLocaleContext) {
|
||||
return ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,8 +24,10 @@ import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.TimeZone;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.sql.DataSource;
|
||||
@@ -580,14 +582,19 @@ public abstract class AbstractJasperReportsView extends AbstractUrlBasedView {
|
||||
*/
|
||||
protected void exposeLocalizationContext(Map<String, Object> model, HttpServletRequest request) {
|
||||
RequestContext rc = new RequestContext(request, getServletContext());
|
||||
Locale locale = rc.getLocale();
|
||||
if (!model.containsKey(JRParameter.REPORT_LOCALE)) {
|
||||
model.put(JRParameter.REPORT_LOCALE, rc.getLocale());
|
||||
model.put(JRParameter.REPORT_LOCALE, locale);
|
||||
}
|
||||
TimeZone timeZone = rc.getTimeZone();
|
||||
if (timeZone != null && !model.containsKey(JRParameter.REPORT_TIME_ZONE)) {
|
||||
model.put(JRParameter.REPORT_TIME_ZONE, timeZone);
|
||||
}
|
||||
JasperReport report = getReport();
|
||||
if ((report == null || report.getResourceBundle() == null) &&
|
||||
!model.containsKey(JRParameter.REPORT_RESOURCE_BUNDLE)) {
|
||||
model.put(JRParameter.REPORT_RESOURCE_BUNDLE,
|
||||
new MessageSourceResourceBundle(rc.getMessageSource(), rc.getLocale()));
|
||||
new MessageSourceResourceBundle(rc.getMessageSource(), locale));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.web.servlet.view.velocity;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -408,12 +409,11 @@ public class VelocityView extends AbstractTemplateView {
|
||||
|
||||
// Expose locale-aware DateTool/NumberTool attributes.
|
||||
if (this.dateToolAttribute != null || this.numberToolAttribute != null) {
|
||||
Locale locale = RequestContextUtils.getLocale(request);
|
||||
if (this.dateToolAttribute != null) {
|
||||
velocityContext.put(this.dateToolAttribute, new LocaleAwareDateTool(locale));
|
||||
velocityContext.put(this.dateToolAttribute, new LocaleAwareDateTool(request));
|
||||
}
|
||||
if (this.numberToolAttribute != null) {
|
||||
velocityContext.put(this.numberToolAttribute, new LocaleAwareNumberTool(locale));
|
||||
velocityContext.put(this.numberToolAttribute, new LocaleAwareNumberTool(request));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -528,41 +528,48 @@ public class VelocityView extends AbstractTemplateView {
|
||||
|
||||
|
||||
/**
|
||||
* Subclass of DateTool from Velocity Tools, using a passed-in Locale
|
||||
* (usually the RequestContext Locale) instead of the default Locale.N
|
||||
* Subclass of DateTool from Velocity Tools, using a Spring-resolved
|
||||
* Locale and TimeZone instead of the default Locale.
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getTimeZone
|
||||
*/
|
||||
private static class LocaleAwareDateTool extends DateTool {
|
||||
|
||||
private final Locale locale;
|
||||
private final HttpServletRequest request;
|
||||
|
||||
private LocaleAwareDateTool(Locale locale) {
|
||||
this.locale = locale;
|
||||
public LocaleAwareDateTool(HttpServletRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return this.locale;
|
||||
return RequestContextUtils.getLocale(this.request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getTimeZone() {
|
||||
TimeZone timeZone = RequestContextUtils.getTimeZone(this.request);
|
||||
return (timeZone != null ? timeZone : super.getTimeZone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclass of NumberTool from Velocity Tools, using a passed-in Locale
|
||||
* (usually the RequestContext Locale) instead of the default Locale.
|
||||
* Subclass of NumberTool from Velocity Tools, using a Spring-resolved
|
||||
* Locale instead of the default Locale.
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
|
||||
*/
|
||||
private static class LocaleAwareNumberTool extends NumberTool {
|
||||
|
||||
private final Locale locale;
|
||||
private final HttpServletRequest request;
|
||||
|
||||
private LocaleAwareNumberTool(Locale locale) {
|
||||
this.locale = locale;
|
||||
public LocaleAwareNumberTool(HttpServletRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return this.locale;
|
||||
return RequestContextUtils.getLocale(this.request);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user