001/* 002 * Copyright 2002-2018 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.support; 018 019import java.util.Locale; 020import java.util.Map; 021import java.util.TimeZone; 022 023import javax.servlet.ServletContext; 024import javax.servlet.ServletRequest; 025import javax.servlet.http.HttpServletRequest; 026import javax.servlet.http.HttpServletResponse; 027 028import org.springframework.context.i18n.LocaleContext; 029import org.springframework.context.i18n.TimeZoneAwareLocaleContext; 030import org.springframework.lang.Nullable; 031import org.springframework.ui.context.Theme; 032import org.springframework.ui.context.ThemeSource; 033import org.springframework.util.Assert; 034import org.springframework.util.CollectionUtils; 035import org.springframework.web.context.ContextLoader; 036import org.springframework.web.context.WebApplicationContext; 037import org.springframework.web.context.support.WebApplicationContextUtils; 038import org.springframework.web.servlet.DispatcherServlet; 039import org.springframework.web.servlet.FlashMap; 040import org.springframework.web.servlet.FlashMapManager; 041import org.springframework.web.servlet.LocaleContextResolver; 042import org.springframework.web.servlet.LocaleResolver; 043import org.springframework.web.servlet.ThemeResolver; 044import org.springframework.web.util.UriComponents; 045import org.springframework.web.util.UriComponentsBuilder; 046 047/** 048 * Utility class for easy access to request-specific state which has been 049 * set by the {@link org.springframework.web.servlet.DispatcherServlet}. 050 * 051 * <p>Supports lookup of current WebApplicationContext, LocaleResolver, 052 * Locale, ThemeResolver, Theme, and MultipartResolver. 053 * 054 * @author Juergen Hoeller 055 * @author Rossen Stoyanchev 056 * @since 03.03.2003 057 * @see RequestContext 058 * @see org.springframework.web.servlet.DispatcherServlet 059 */ 060public abstract class RequestContextUtils { 061 062 /** 063 * The name of the bean to use to look up in an implementation of 064 * {@link RequestDataValueProcessor} has been configured. 065 * @since 4.2.1 066 */ 067 public static final String REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME = "requestDataValueProcessor"; 068 069 070 /** 071 * Look for the WebApplicationContext associated with the DispatcherServlet 072 * that has initiated request processing, and for the global context if none 073 * was found associated with the current request. The global context will 074 * be found via the ServletContext or via ContextLoader's current context. 075 * <p>NOTE: This variant remains compatible with Servlet 2.5, explicitly 076 * checking a given ServletContext instead of deriving it from the request. 077 * @param request current HTTP request 078 * @param servletContext current servlet context 079 * @return the request-specific WebApplicationContext, or the global one 080 * if no request-specific context has been found, or {@code null} if none 081 * @since 4.2.1 082 * @see DispatcherServlet#WEB_APPLICATION_CONTEXT_ATTRIBUTE 083 * @see WebApplicationContextUtils#getWebApplicationContext(ServletContext) 084 * @see ContextLoader#getCurrentWebApplicationContext() 085 */ 086 @Nullable 087 public static WebApplicationContext findWebApplicationContext( 088 HttpServletRequest request, @Nullable ServletContext servletContext) { 089 090 WebApplicationContext webApplicationContext = (WebApplicationContext) request.getAttribute( 091 DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE); 092 if (webApplicationContext == null) { 093 if (servletContext != null) { 094 webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext); 095 } 096 if (webApplicationContext == null) { 097 webApplicationContext = ContextLoader.getCurrentWebApplicationContext(); 098 } 099 } 100 return webApplicationContext; 101 } 102 103 /** 104 * Look for the WebApplicationContext associated with the DispatcherServlet 105 * that has initiated request processing, and for the global context if none 106 * was found associated with the current request. The global context will 107 * be found via the ServletContext or via ContextLoader's current context. 108 * <p>NOTE: This variant requires Servlet 3.0+ and is generally recommended 109 * for forward-looking custom user code. 110 * @param request current HTTP request 111 * @return the request-specific WebApplicationContext, or the global one 112 * if no request-specific context has been found, or {@code null} if none 113 * @since 4.2.1 114 * @see #findWebApplicationContext(HttpServletRequest, ServletContext) 115 * @see ServletRequest#getServletContext() 116 * @see ContextLoader#getCurrentWebApplicationContext() 117 */ 118 @Nullable 119 public static WebApplicationContext findWebApplicationContext(HttpServletRequest request) { 120 return findWebApplicationContext(request, request.getServletContext()); 121 } 122 123 /** 124 * Return the LocaleResolver that has been bound to the request by the 125 * DispatcherServlet. 126 * @param request current HTTP request 127 * @return the current LocaleResolver, or {@code null} if not found 128 */ 129 @Nullable 130 public static LocaleResolver getLocaleResolver(HttpServletRequest request) { 131 return (LocaleResolver) request.getAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE); 132 } 133 134 /** 135 * Retrieve the current locale from the given request, using the 136 * LocaleResolver bound to the request by the DispatcherServlet 137 * (if available), falling back to the request's accept-header Locale. 138 * <p>This method serves as a straightforward alternative to the standard 139 * Servlet {@link javax.servlet.http.HttpServletRequest#getLocale()} method, 140 * falling back to the latter if no more specific locale has been found. 141 * <p>Consider using {@link org.springframework.context.i18n.LocaleContextHolder#getLocale()} 142 * which will normally be populated with the same Locale. 143 * @param request current HTTP request 144 * @return the current locale for the given request, either from the 145 * LocaleResolver or from the plain request itself 146 * @see #getLocaleResolver 147 * @see org.springframework.context.i18n.LocaleContextHolder#getLocale() 148 */ 149 public static Locale getLocale(HttpServletRequest request) { 150 LocaleResolver localeResolver = getLocaleResolver(request); 151 return (localeResolver != null ? localeResolver.resolveLocale(request) : request.getLocale()); 152 } 153 154 /** 155 * Retrieve the current time zone from the given request, using the 156 * TimeZoneAwareLocaleResolver bound to the request by the DispatcherServlet 157 * (if available), falling back to the system's default time zone. 158 * <p>Note: This method returns {@code null} if no specific time zone can be 159 * resolved for the given request. This is in contrast to {@link #getLocale} 160 * where there is always the request's accept-header locale to fall back to. 161 * <p>Consider using {@link org.springframework.context.i18n.LocaleContextHolder#getTimeZone()} 162 * which will normally be populated with the same TimeZone: That method only 163 * differs in terms of its fallback to the system time zone if the LocaleResolver 164 * hasn't provided a specific time zone (instead of this method's {@code null}). 165 * @param request current HTTP request 166 * @return the current time zone for the given request, either from the 167 * TimeZoneAwareLocaleResolver or {@code null} if none associated 168 * @see #getLocaleResolver 169 * @see org.springframework.context.i18n.LocaleContextHolder#getTimeZone() 170 */ 171 @Nullable 172 public static TimeZone getTimeZone(HttpServletRequest request) { 173 LocaleResolver localeResolver = getLocaleResolver(request); 174 if (localeResolver instanceof LocaleContextResolver) { 175 LocaleContext localeContext = ((LocaleContextResolver) localeResolver).resolveLocaleContext(request); 176 if (localeContext instanceof TimeZoneAwareLocaleContext) { 177 return ((TimeZoneAwareLocaleContext) localeContext).getTimeZone(); 178 } 179 } 180 return null; 181 } 182 183 /** 184 * Return the ThemeResolver that has been bound to the request by the 185 * DispatcherServlet. 186 * @param request current HTTP request 187 * @return the current ThemeResolver, or {@code null} if not found 188 */ 189 @Nullable 190 public static ThemeResolver getThemeResolver(HttpServletRequest request) { 191 return (ThemeResolver) request.getAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE); 192 } 193 194 /** 195 * Return the ThemeSource that has been bound to the request by the 196 * DispatcherServlet. 197 * @param request current HTTP request 198 * @return the current ThemeSource 199 */ 200 @Nullable 201 public static ThemeSource getThemeSource(HttpServletRequest request) { 202 return (ThemeSource) request.getAttribute(DispatcherServlet.THEME_SOURCE_ATTRIBUTE); 203 } 204 205 /** 206 * Retrieves the current theme from the given request, using the ThemeResolver 207 * and ThemeSource bound to the request by the DispatcherServlet. 208 * @param request current HTTP request 209 * @return the current theme, or {@code null} if not found 210 * @see #getThemeResolver 211 */ 212 @Nullable 213 public static Theme getTheme(HttpServletRequest request) { 214 ThemeResolver themeResolver = getThemeResolver(request); 215 ThemeSource themeSource = getThemeSource(request); 216 if (themeResolver != null && themeSource != null) { 217 String themeName = themeResolver.resolveThemeName(request); 218 return themeSource.getTheme(themeName); 219 } 220 else { 221 return null; 222 } 223 } 224 225 /** 226 * Return read-only "input" flash attributes from request before redirect. 227 * @param request current request 228 * @return a read-only Map, or {@code null} if not found 229 * @see FlashMap 230 */ 231 @SuppressWarnings("unchecked") 232 @Nullable 233 public static Map<String, ?> getInputFlashMap(HttpServletRequest request) { 234 return (Map<String, ?>) request.getAttribute(DispatcherServlet.INPUT_FLASH_MAP_ATTRIBUTE); 235 } 236 237 /** 238 * Return "output" FlashMap to save attributes for request after redirect. 239 * @param request current request 240 * @return a {@link FlashMap} instance, never {@code null} within a 241 * {@code DispatcherServlet}-handled request 242 */ 243 public static FlashMap getOutputFlashMap(HttpServletRequest request) { 244 return (FlashMap) request.getAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE); 245 } 246 247 /** 248 * Return the {@code FlashMapManager} instance to save flash attributes. 249 * <p>As of 5.0 the convenience method {@link #saveOutputFlashMap} may be 250 * used to save the "output" FlashMap. 251 * @param request the current request 252 * @return a {@link FlashMapManager} instance, never {@code null} within a 253 * {@code DispatcherServlet}-handled request 254 */ 255 @Nullable 256 public static FlashMapManager getFlashMapManager(HttpServletRequest request) { 257 return (FlashMapManager) request.getAttribute(DispatcherServlet.FLASH_MAP_MANAGER_ATTRIBUTE); 258 } 259 260 /** 261 * Convenience method that retrieves the {@link #getOutputFlashMap "output" 262 * FlashMap}, updates it with the path and query params of the target URL, 263 * and then saves it using the {@link #getFlashMapManager FlashMapManager}. 264 * @param location the target URL for the redirect 265 * @param request the current request 266 * @param response the current response 267 * @since 5.0 268 */ 269 public static void saveOutputFlashMap(String location, HttpServletRequest request, HttpServletResponse response) { 270 FlashMap flashMap = getOutputFlashMap(request); 271 if (CollectionUtils.isEmpty(flashMap)) { 272 return; 273 } 274 275 UriComponents uriComponents = UriComponentsBuilder.fromUriString(location).build(); 276 flashMap.setTargetRequestPath(uriComponents.getPath()); 277 flashMap.addTargetRequestParams(uriComponents.getQueryParams()); 278 279 FlashMapManager manager = getFlashMapManager(request); 280 Assert.state(manager != null, "No FlashMapManager. Is this a DispatcherServlet handled request?"); 281 manager.saveOutputFlashMap(flashMap, request, response); 282 } 283 284}