001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.i18n; 018 019import java.util.Locale; 020import java.util.TimeZone; 021import javax.servlet.http.HttpServletRequest; 022import javax.servlet.http.HttpServletResponse; 023 024import org.springframework.context.i18n.LocaleContext; 025import org.springframework.context.i18n.TimeZoneAwareLocaleContext; 026import org.springframework.web.util.WebUtils; 027 028/** 029 * {@link org.springframework.web.servlet.LocaleResolver} implementation that 030 * uses a locale attribute in the user's session in case of a custom setting, 031 * with a fallback to the specified default locale or the request's 032 * accept-header locale. 033 * 034 * <p>This is most appropriate if the application needs user sessions anyway, 035 * i.e. when the {@code HttpSession} does not have to be created just for storing 036 * the user's locale. The session may optionally contain an associated time zone 037 * attribute as well; alternatively, you may specify a default time zone. 038 * 039 * <p>Custom controllers can override the user's locale and time zone by calling 040 * {@code #setLocale(Context)} on the resolver, e.g. responding to a locale change 041 * request. As a more convenient alternative, consider using 042 * {@link org.springframework.web.servlet.support.RequestContext#changeLocale}. 043 * 044 * <p>In contrast to {@link CookieLocaleResolver}, this strategy stores locally 045 * chosen locale settings in the Servlet container's {@code HttpSession}. As a 046 * consequence, those settings are just temporary for each session and therefore 047 * lost when each session terminates. 048 * 049 * <p>Note that there is no direct relationship with external session management 050 * mechanisms such as the "Spring Session" project. This {@code LocaleResolver} 051 * will simply evaluate and modify corresponding {@code HttpSession} attributes 052 * against the current {@code HttpServletRequest}. 053 * 054 * @author Juergen Hoeller 055 * @since 27.02.2003 056 * @see #setDefaultLocale 057 * @see #setDefaultTimeZone 058 */ 059public class SessionLocaleResolver extends AbstractLocaleContextResolver { 060 061 /** 062 * Name of the session attribute that holds the Locale. 063 * Only used internally by this implementation. 064 * <p>Use {@code RequestContext(Utils).getLocale()} 065 * to retrieve the current locale in controllers or views. 066 * @see org.springframework.web.servlet.support.RequestContext#getLocale 067 * @see org.springframework.web.servlet.support.RequestContextUtils#getLocale 068 */ 069 public static final String LOCALE_SESSION_ATTRIBUTE_NAME = SessionLocaleResolver.class.getName() + ".LOCALE"; 070 071 /** 072 * Name of the session attribute that holds the TimeZone. 073 * Only used internally by this implementation. 074 * <p>Use {@code RequestContext(Utils).getTimeZone()} 075 * to retrieve the current time zone in controllers or views. 076 * @see org.springframework.web.servlet.support.RequestContext#getTimeZone 077 * @see org.springframework.web.servlet.support.RequestContextUtils#getTimeZone 078 */ 079 public static final String TIME_ZONE_SESSION_ATTRIBUTE_NAME = SessionLocaleResolver.class.getName() + ".TIME_ZONE"; 080 081 082 private String localeAttributeName = LOCALE_SESSION_ATTRIBUTE_NAME; 083 084 private String timeZoneAttributeName = TIME_ZONE_SESSION_ATTRIBUTE_NAME; 085 086 087 /** 088 * Specify the name of the corresponding attribute in the {@code HttpSession}, 089 * holding the current {@link Locale} value. 090 * <p>The default is an internal {@link #LOCALE_SESSION_ATTRIBUTE_NAME}. 091 * @since 4.3.8 092 */ 093 public void setLocaleAttributeName(String localeAttributeName) { 094 this.localeAttributeName = localeAttributeName; 095 } 096 097 /** 098 * Specify the name of the corresponding attribute in the {@code HttpSession}, 099 * holding the current {@link TimeZone} value. 100 * <p>The default is an internal {@link #TIME_ZONE_SESSION_ATTRIBUTE_NAME}. 101 * @since 4.3.8 102 */ 103 public void setTimeZoneAttributeName(String timeZoneAttributeName) { 104 this.timeZoneAttributeName = timeZoneAttributeName; 105 } 106 107 108 @Override 109 public Locale resolveLocale(HttpServletRequest request) { 110 Locale locale = (Locale) WebUtils.getSessionAttribute(request, this.localeAttributeName); 111 if (locale == null) { 112 locale = determineDefaultLocale(request); 113 } 114 return locale; 115 } 116 117 @Override 118 public LocaleContext resolveLocaleContext(final HttpServletRequest request) { 119 return new TimeZoneAwareLocaleContext() { 120 @Override 121 public Locale getLocale() { 122 Locale locale = (Locale) WebUtils.getSessionAttribute(request, localeAttributeName); 123 if (locale == null) { 124 locale = determineDefaultLocale(request); 125 } 126 return locale; 127 } 128 @Override 129 public TimeZone getTimeZone() { 130 TimeZone timeZone = (TimeZone) WebUtils.getSessionAttribute(request, timeZoneAttributeName); 131 if (timeZone == null) { 132 timeZone = determineDefaultTimeZone(request); 133 } 134 return timeZone; 135 } 136 }; 137 } 138 139 @Override 140 public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) { 141 Locale locale = null; 142 TimeZone timeZone = null; 143 if (localeContext != null) { 144 locale = localeContext.getLocale(); 145 if (localeContext instanceof TimeZoneAwareLocaleContext) { 146 timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone(); 147 } 148 } 149 WebUtils.setSessionAttribute(request, this.localeAttributeName, locale); 150 WebUtils.setSessionAttribute(request, this.timeZoneAttributeName, timeZone); 151 } 152 153 154 /** 155 * Determine the default locale for the given request, 156 * Called if no Locale session attribute has been found. 157 * <p>The default implementation returns the specified default locale, 158 * if any, else falls back to the request's accept-header locale. 159 * @param request the request to resolve the locale for 160 * @return the default locale (never {@code null}) 161 * @see #setDefaultLocale 162 * @see javax.servlet.http.HttpServletRequest#getLocale() 163 */ 164 protected Locale determineDefaultLocale(HttpServletRequest request) { 165 Locale defaultLocale = getDefaultLocale(); 166 if (defaultLocale == null) { 167 defaultLocale = request.getLocale(); 168 } 169 return defaultLocale; 170 } 171 172 /** 173 * Determine the default time zone for the given request, 174 * Called if no TimeZone session attribute has been found. 175 * <p>The default implementation returns the specified default time zone, 176 * if any, or {@code null} otherwise. 177 * @param request the request to resolve the time zone for 178 * @return the default time zone (or {@code null} if none defined) 179 * @see #setDefaultTimeZone 180 */ 181 protected TimeZone determineDefaultTimeZone(HttpServletRequest request) { 182 return getDefaultTimeZone(); 183 } 184 185}