0
# Support Utilities
1
2
Spring MVC provides various support classes and utilities for servlet initialization, request context access, URI building, internationalization, and other cross-cutting concerns.
3
4
## Capabilities
5
6
### Servlet Initialization
7
8
#### AbstractDispatcherServletInitializer
9
10
Base class for WebApplicationInitializer implementations that register a DispatcherServlet in a Servlet 3.0+ environment.
11
12
```java { .api }
13
/**
14
* Base class for WebApplicationInitializer implementations that register a DispatcherServlet.
15
*/
16
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {
17
18
/** Create the servlet application context */
19
protected abstract WebApplicationContext createServletApplicationContext();
20
21
/** Specify servlet mappings for the DispatcherServlet */
22
protected abstract String[] getServletMappings();
23
24
/** Return the name to use for the DispatcherServlet */
25
protected String getServletName();
26
27
/** Get application context initializers for the servlet context */
28
protected ApplicationContextInitializer<?>[] getServletApplicationContextInitializers();
29
30
/** Get filters to apply to the DispatcherServlet */
31
protected Filter[] getServletFilters();
32
33
/** Return whether async is supported for the DispatcherServlet */
34
protected boolean isAsyncSupported();
35
36
/** Return the order to use for the DispatcherServlet */
37
protected int getOrder();
38
39
/** Customize DispatcherServlet registration */
40
protected void customizeRegistration(ServletRegistration.Dynamic registration);
41
}
42
```
43
44
#### AbstractAnnotationConfigDispatcherServletInitializer
45
46
WebApplicationInitializer to register a DispatcherServlet and use Java-based Spring configuration.
47
48
```java { .api }
49
/**
50
* WebApplicationInitializer implementation that registers a DispatcherServlet configured with annotated classes.
51
*/
52
public abstract class AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer {
53
54
/** Specify @Configuration and/or @Component classes for the root application context */
55
protected abstract Class<?>[] getRootConfigClasses();
56
57
/** Specify @Configuration and/or @Component classes for the servlet application context */
58
protected abstract Class<?>[] getServletConfigClasses();
59
}
60
```
61
62
**Usage Examples:**
63
64
```java
65
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
66
67
@Override
68
protected Class<?>[] getRootConfigClasses() {
69
return new Class<?>[] { RootConfig.class };
70
}
71
72
@Override
73
protected Class<?>[] getServletConfigClasses() {
74
return new Class<?>[] { WebConfig.class };
75
}
76
77
@Override
78
protected String[] getServletMappings() {
79
return new String[] { "/" };
80
}
81
82
@Override
83
protected Filter[] getServletFilters() {
84
return new Filter[] {
85
new CharacterEncodingFilter("UTF-8", true),
86
new HiddenHttpMethodFilter(),
87
new HttpPutFormContentFilter()
88
};
89
}
90
91
@Override
92
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
93
registration.setMultipartConfig(new MultipartConfigElement("/tmp", 5000000, 5000000, 0));
94
registration.setAsyncSupported(true);
95
}
96
}
97
98
// Alternative with manual configuration
99
public class ManualWebAppInitializer extends AbstractDispatcherServletInitializer {
100
101
@Override
102
protected WebApplicationContext createServletApplicationContext() {
103
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
104
context.register(WebConfig.class);
105
return context;
106
}
107
108
@Override
109
protected String[] getServletMappings() {
110
return new String[] { "/api/*" };
111
}
112
113
@Override
114
protected WebApplicationContext createRootApplicationContext() {
115
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
116
context.register(RootConfig.class);
117
return context;
118
}
119
}
120
```
121
122
### Request Context Utilities
123
124
#### RequestContextUtils
125
126
Utility class for easy access to request-specific state established by DispatcherServlet.
127
128
```java { .api }
129
/**
130
* Utility class for easy access to request-specific state which has been set by the DispatcherServlet.
131
*/
132
public abstract class RequestContextUtils {
133
134
/** Find WebApplicationContext for this request */
135
public static WebApplicationContext findWebApplicationContext(HttpServletRequest request);
136
137
/** Find WebApplicationContext, with fallback to global context */
138
public static WebApplicationContext findWebApplicationContext(HttpServletRequest request, ServletContext servletContext);
139
140
/** Get LocaleResolver for this request */
141
public static LocaleResolver getLocaleResolver(HttpServletRequest request);
142
143
/** Get Locale for this request */
144
public static Locale getLocale(HttpServletRequest request);
145
146
/** Get TimeZone for this request */
147
public static TimeZone getTimeZone(HttpServletRequest request);
148
149
/** Get ThemeResolver for this request */
150
public static ThemeResolver getThemeResolver(HttpServletRequest request);
151
152
/** Get Theme for this request */
153
public static Theme getTheme(HttpServletRequest request);
154
155
/** Get input FlashMap for this request */
156
public static FlashMap getInputFlashMap(HttpServletRequest request);
157
158
/** Get output FlashMap for this request */
159
public static FlashMap getOutputFlashMap(HttpServletRequest request);
160
161
/** Get FlashMapManager for this request */
162
public static FlashMapManager getFlashMapManager(HttpServletRequest request);
163
164
/** Get MultipartResolver for this request */
165
public static MultipartResolver getMultipartResolver(HttpServletRequest request);
166
}
167
```
168
169
**Usage Examples:**
170
171
```java
172
@Controller
173
public class UtilityController {
174
175
@GetMapping("/context-info")
176
@ResponseBody
177
public Map<String, Object> getContextInfo(HttpServletRequest request) {
178
Map<String, Object> info = new HashMap<>();
179
180
// Get application context
181
WebApplicationContext context = RequestContextUtils.findWebApplicationContext(request);
182
info.put("contextId", context.getId());
183
info.put("displayName", context.getDisplayName());
184
185
// Get locale information
186
Locale locale = RequestContextUtils.getLocale(request);
187
TimeZone timeZone = RequestContextUtils.getTimeZone(request);
188
info.put("locale", locale.toString());
189
info.put("timeZone", timeZone.getID());
190
191
// Get flash map
192
FlashMap inputFlashMap = RequestContextUtils.getInputFlashMap(request);
193
if (inputFlashMap != null && !inputFlashMap.isEmpty()) {
194
info.put("flashAttributes", inputFlashMap);
195
}
196
197
return info;
198
}
199
200
@PostMapping("/set-flash")
201
public String setFlashAttribute(HttpServletRequest request, RedirectAttributes redirectAttributes) {
202
// Using RedirectAttributes (preferred)
203
redirectAttributes.addFlashAttribute("message", "Operation successful");
204
205
// Or using RequestContextUtils directly
206
FlashMap outputFlashMap = RequestContextUtils.getOutputFlashMap(request);
207
if (outputFlashMap != null) {
208
outputFlashMap.put("timestamp", System.currentTimeMillis());
209
}
210
211
return "redirect:/context-info";
212
}
213
}
214
```
215
216
### URI Building Utilities
217
218
#### ServletUriComponentsBuilder
219
220
UriComponentsBuilder with additional static factory methods to create URLs based on the current HttpServletRequest.
221
222
```java { .api }
223
/**
224
* UriComponentsBuilder with additional static factory methods based on the current HttpServletRequest.
225
*/
226
public class ServletUriComponentsBuilder extends UriComponentsBuilder {
227
228
/** Create builder from context path of current request */
229
public static ServletUriComponentsBuilder fromContextPath(HttpServletRequest request);
230
231
/** Create builder from servlet mapping of current request */
232
public static ServletUriComponentsBuilder fromServletMapping(HttpServletRequest request);
233
234
/** Create builder from request URI of current request */
235
public static ServletUriComponentsBuilder fromRequestUri(HttpServletRequest request);
236
237
/** Create builder from current request */
238
public static ServletUriComponentsBuilder fromRequest(HttpServletRequest request);
239
240
/** Create builder from current context path (requires request context) */
241
public static ServletUriComponentsBuilder fromCurrentContextPath();
242
243
/** Create builder from current servlet mapping (requires request context) */
244
public static ServletUriComponentsBuilder fromCurrentServletMapping();
245
246
/** Create builder from current request URI (requires request context) */
247
public static ServletUriComponentsBuilder fromCurrentRequestUri();
248
249
/** Create builder from current request (requires request context) */
250
public static ServletUriComponentsBuilder fromCurrentRequest();
251
252
/** Remove the specified query parameters */
253
public ServletUriComponentsBuilder removeQueryParams(String... queryParams);
254
255
/** Replace the query string entirely */
256
public ServletUriComponentsBuilder replaceQuery(String query);
257
}
258
```
259
260
**Usage Examples:**
261
262
```java
263
@RestController
264
@RequestMapping("/api/users")
265
public class UserApiController {
266
267
@PostMapping
268
public ResponseEntity<User> createUser(@RequestBody User user, HttpServletRequest request) {
269
User savedUser = userService.save(user);
270
271
// Build location header using current request
272
URI location = ServletUriComponentsBuilder
273
.fromCurrentRequest()
274
.path("/{id}")
275
.buildAndExpand(savedUser.getId())
276
.toUri();
277
278
return ResponseEntity.created(location).body(savedUser);
279
}
280
281
@GetMapping
282
public ResponseEntity<PagedResponse<User>> getUsers(
283
@RequestParam(defaultValue = "0") int page,
284
@RequestParam(defaultValue = "10") int size,
285
HttpServletRequest request) {
286
287
Page<User> users = userService.findAll(PageRequest.of(page, size));
288
289
// Build pagination links
290
String baseUrl = ServletUriComponentsBuilder
291
.fromCurrentRequest()
292
.replaceQueryParams(null) // Remove all query params
293
.toUriString();
294
295
Map<String, String> links = new HashMap<>();
296
links.put("self", baseUrl + "?page=" + page + "&size=" + size);
297
298
if (users.hasNext()) {
299
links.put("next", baseUrl + "?page=" + (page + 1) + "&size=" + size);
300
}
301
if (users.hasPrevious()) {
302
links.put("prev", baseUrl + "?page=" + (page - 1) + "&size=" + size);
303
}
304
305
PagedResponse<User> response = new PagedResponse<>(users.getContent(), links);
306
return ResponseEntity.ok(response);
307
}
308
309
@GetMapping("/search")
310
public String buildSearchUrl(HttpServletRequest request) {
311
return ServletUriComponentsBuilder
312
.fromRequest(request)
313
.replaceQuery("q={keyword}&type={type}")
314
.build()
315
.toUriString();
316
}
317
}
318
319
@Controller
320
public class WebController {
321
322
@GetMapping("/form")
323
public String showForm(Model model) {
324
// Build form action URL
325
String actionUrl = ServletUriComponentsBuilder
326
.fromCurrentServletMapping()
327
.path("/submit")
328
.toUriString();
329
330
model.addAttribute("actionUrl", actionUrl);
331
return "form";
332
}
333
334
@PostMapping("/submit")
335
public String submitForm(@ModelAttribute FormData formData) {
336
// Process form
337
return "redirect:" + ServletUriComponentsBuilder
338
.fromCurrentContextPath()
339
.path("/success")
340
.queryParam("id", formData.getId())
341
.toUriString();
342
}
343
}
344
```
345
346
### Internationalization Support
347
348
#### LocaleResolver Implementations
349
350
See the main documentation for LocaleResolver interface. Here are additional implementation details:
351
352
```java
353
@Configuration
354
public class LocaleConfig {
355
356
@Bean
357
public LocaleResolver localeResolver() {
358
CookieLocaleResolver resolver = new CookieLocaleResolver();
359
resolver.setDefaultLocale(Locale.ENGLISH);
360
resolver.setCookieName("locale");
361
resolver.setCookieMaxAge(3600);
362
resolver.setCookiePath("/");
363
return resolver;
364
}
365
366
@Bean
367
public LocaleChangeInterceptor localeChangeInterceptor() {
368
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
369
interceptor.setParamName("lang");
370
return interceptor;
371
}
372
373
@Override
374
public void addInterceptors(InterceptorRegistry registry) {
375
registry.addInterceptor(localeChangeInterceptor());
376
}
377
}
378
379
@Controller
380
public class LocaleController {
381
382
@GetMapping("/locale-info")
383
@ResponseBody
384
public Map<String, Object> getLocaleInfo(HttpServletRequest request, HttpServletResponse response) {
385
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
386
Locale currentLocale = localeResolver.resolveLocale(request);
387
388
Map<String, Object> info = new HashMap<>();
389
info.put("currentLocale", currentLocale.toString());
390
info.put("language", currentLocale.getLanguage());
391
info.put("country", currentLocale.getCountry());
392
info.put("displayName", currentLocale.getDisplayName());
393
394
return info;
395
}
396
397
@PostMapping("/change-locale")
398
public String changeLocale(@RequestParam String locale,
399
HttpServletRequest request,
400
HttpServletResponse response) {
401
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
402
localeResolver.setLocale(request, response, Locale.forLanguageTag(locale));
403
404
String referer = request.getHeader("Referer");
405
return "redirect:" + (referer != null ? referer : "/");
406
}
407
}
408
```
409
410
### Flash Map Support
411
412
#### FlashMap and FlashMapManager
413
414
See main documentation for interfaces. Here are usage patterns:
415
416
```java
417
@Controller
418
public class FlashMapController {
419
420
@PostMapping("/process")
421
public String processData(@ModelAttribute ProcessData data,
422
HttpServletRequest request,
423
RedirectAttributes redirectAttributes) {
424
425
try {
426
processService.process(data);
427
428
// Using RedirectAttributes (preferred)
429
redirectAttributes.addFlashAttribute("successMessage", "Data processed successfully");
430
redirectAttributes.addFlashAttribute("processedData", data);
431
432
} catch (ProcessingException e) {
433
// Using FlashMap directly for complex scenarios
434
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
435
flashMap.put("errorMessage", e.getMessage());
436
flashMap.put("errorCode", e.getErrorCode());
437
flashMap.put("inputData", data);
438
439
// Set target for flash attributes
440
flashMap.setTargetRequestPath("/error");
441
Map<String, String> targetParams = new HashMap<>();
442
targetParams.put("type", "processing");
443
flashMap.setTargetRequestParams(new LinkedMultiValueMap<>(targetParams));
444
445
return "redirect:/error?type=processing";
446
}
447
448
return "redirect:/success";
449
}
450
451
@GetMapping("/success")
452
public String showSuccess(Model model, HttpServletRequest request) {
453
// Flash attributes are automatically added to model
454
// But can also be accessed directly
455
FlashMap inputFlashMap = RequestContextUtils.getInputFlashMap(request);
456
if (inputFlashMap != null) {
457
log.info("Flash attributes received: {}", inputFlashMap.keySet());
458
}
459
460
return "success";
461
}
462
463
@GetMapping("/error")
464
public String showError(@RequestParam String type, Model model, HttpServletRequest request) {
465
FlashMap inputFlashMap = RequestContextUtils.getInputFlashMap(request);
466
if (inputFlashMap != null && inputFlashMap.containsKey("errorMessage")) {
467
model.addAttribute("errorDetails", inputFlashMap);
468
}
469
470
return "error";
471
}
472
}
473
```
474
475
### JSP Tag Library Support
476
477
#### RequestContextAwareTag
478
479
Abstract base class for JSP tags that need access to the RequestContext.
480
481
```java { .api }
482
/**
483
* Superclass for all tags that require a RequestContext.
484
*/
485
public abstract class RequestContextAwareTag extends TagSupport {
486
487
/** Get the current RequestContext */
488
protected final RequestContext getRequestContext();
489
490
/** Template method for tag start processing */
491
protected abstract int doStartTagInternal() throws Exception;
492
}
493
```
494
495
#### MessageTag
496
497
JSP tag for message resolution using MessageSource.
498
499
```java { .api }
500
/**
501
* Custom tag for retrieving message from MessageSource.
502
*/
503
public class MessageTag extends RequestContextAwareTag {
504
505
/** Set the message code */
506
public void setCode(String code);
507
508
/** Set message arguments */
509
public void setArguments(Object arguments);
510
511
/** Set MessageSourceResolvable object */
512
public void setMessage(MessageSourceResolvable message);
513
514
/** Set scope for storing the result */
515
public void setScope(String scope);
516
517
/** Set variable name for storing the result */
518
public void setVar(String var);
519
520
/** Set text to output if message not found */
521
public void setText(String text);
522
523
/** Set HTML escaping flag */
524
public void setHtmlEscape(boolean htmlEscape);
525
}
526
```
527
528
#### UrlTag
529
530
JSP tag for creating URLs with proper encoding and context path handling.
531
532
```java { .api }
533
/**
534
* JSP tag for creating URLs. Modeled after the JSTL c:url tag.
535
*/
536
public class UrlTag extends RequestContextAwareTag {
537
538
/** Set the URL value */
539
public void setValue(String value);
540
541
/** Set the context path */
542
public void setContext(String context);
543
544
/** Set variable name for storing the result */
545
public void setVar(String var);
546
547
/** Set scope for storing the result */
548
public void setScope(String scope);
549
550
/** Set HTML escaping flag */
551
public void setHtmlEscape(boolean htmlEscape);
552
553
/** Set JavaScript escaping flag */
554
public void setJavaScriptEscape(boolean javaScriptEscape);
555
}
556
```
557
558
**JSP Tag Usage Examples:**
559
560
```jsp
561
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
562
563
<!-- Message resolution -->
564
<spring:message code="welcome.message" />
565
<spring:message code="user.greeting" arguments="${user.name}" />
566
<spring:message code="error.required" var="requiredMsg" />
567
568
<!-- URL creation -->
569
<spring:url value="/users/${user.id}" var="userUrl" />
570
<a href="${userUrl}">View User</a>
571
572
<spring:url value="/static/css/styles.css" context="/myapp" var="cssUrl" />
573
<link rel="stylesheet" href="${cssUrl}" />
574
```
575
576
### Complete Internationalization Support
577
578
#### LocaleResolver Interface
579
580
```java { .api }
581
/**
582
* Interface for web-based locale resolution strategies.
583
*/
584
public interface LocaleResolver {
585
586
/** Resolve the locale for the given request */
587
Locale resolveLocale(HttpServletRequest request);
588
589
/** Set the current locale */
590
void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale);
591
}
592
```
593
594
#### AcceptHeaderLocaleResolver
595
596
```java { .api }
597
/**
598
* LocaleResolver implementation that uses the primary locale specified in the Accept-Language header.
599
*/
600
public class AcceptHeaderLocaleResolver implements LocaleResolver {
601
602
/** Set supported locales */
603
public void setSupportedLocales(List<Locale> locales);
604
605
/** Get supported locales */
606
public List<Locale> getSupportedLocales();
607
608
/** Set default locale */
609
public void setDefaultLocale(Locale defaultLocale);
610
611
/** Get default locale */
612
public Locale getDefaultLocale();
613
}
614
```
615
616
#### SessionLocaleResolver
617
618
```java { .api }
619
/**
620
* LocaleResolver implementation that uses a locale attribute in the user's session.
621
*/
622
public class SessionLocaleResolver implements LocaleResolver {
623
624
/** Set the name of the session attribute holding the locale */
625
public void setLocaleAttributeName(String localeAttributeName);
626
627
/** Get the session attribute name */
628
public String getLocaleAttributeName();
629
630
/** Set default locale */
631
public void setDefaultLocale(Locale defaultLocale);
632
633
/** Set default time zone */
634
public void setDefaultTimeZone(TimeZone defaultTimeZone);
635
}
636
```
637
638
**Complete Internationalization Configuration:**
639
640
```java
641
@Configuration
642
public class CompleteI18nConfig {
643
644
@Bean
645
public MessageSource messageSource() {
646
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
647
messageSource.setBasenames("messages", "validation");
648
messageSource.setDefaultEncoding("UTF-8");
649
messageSource.setCacheSeconds(3600);
650
messageSource.setFallbackToSystemLocale(false);
651
return messageSource;
652
}
653
654
@Bean
655
public LocaleResolver localeResolver() {
656
SessionLocaleResolver resolver = new SessionLocaleResolver();
657
resolver.setDefaultLocale(Locale.ENGLISH);
658
resolver.setDefaultTimeZone(TimeZone.getTimeZone("UTC"));
659
return resolver;
660
}
661
662
@Bean
663
public LocaleChangeInterceptor localeChangeInterceptor() {
664
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
665
interceptor.setParamName("lang");
666
interceptor.setHttpMethods("GET", "POST");
667
interceptor.setIgnoreInvalidLocale(true);
668
return interceptor;
669
}
670
671
// Alternative with Accept-Language header
672
@Bean
673
public LocaleResolver acceptHeaderLocaleResolver() {
674
AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver();
675
resolver.setSupportedLocales(Arrays.asList(
676
Locale.ENGLISH,
677
Locale.FRENCH,
678
Locale.GERMAN,
679
new Locale("es")
680
));
681
resolver.setDefaultLocale(Locale.ENGLISH);
682
return resolver;
683
}
684
}
685
```
686
687
### Exception Handling Utilities
688
689
```java
690
@ControllerAdvice
691
public class GlobalExceptionHandler {
692
693
@ExceptionHandler(NoHandlerFoundException.class)
694
public ModelAndView handleNotFound(NoHandlerFoundException ex, HttpServletRequest request) {
695
ModelAndView mv = new ModelAndView("error/404");
696
mv.addObject("url", ex.getRequestURL());
697
mv.addObject("method", ex.getHttpMethod());
698
mv.addObject("message", "The requested resource was not found");
699
mv.setStatus(HttpStatus.NOT_FOUND);
700
return mv;
701
}
702
703
@ExceptionHandler(Exception.class)
704
public ModelAndView handleGeneral(Exception ex, HttpServletRequest request) {
705
ModelAndView mv = new ModelAndView("error/500");
706
mv.addObject("exception", ex);
707
mv.addObject("url", request.getRequestURL().toString());
708
mv.addObject("timestamp", new Date());
709
mv.setStatus(HttpStatus.INTERNAL_SERVER_ERROR);
710
711
// Add request context information
712
WebApplicationContext context = RequestContextUtils.findWebApplicationContext(request);
713
if (context != null) {
714
mv.addObject("contextInfo", context.getDisplayName());
715
}
716
717
return mv;
718
}
719
}
720
```