1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package cz.zcu.mre.config;
23
24 import java.util.concurrent.TimeUnit;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27 import org.springframework.context.MessageSource;
28 import org.springframework.context.annotation.Bean;
29 import org.springframework.context.annotation.Configuration;
30 import org.springframework.context.annotation.Description;
31 import org.springframework.context.support.ReloadableResourceBundleMessageSource;
32 import org.springframework.core.Ordered;
33 import org.springframework.core.annotation.Order;
34 import org.springframework.format.FormatterRegistry;
35 import org.springframework.format.support.FormattingConversionService;
36 import org.springframework.http.CacheControl;
37 import org.springframework.stereotype.Controller;
38 import org.springframework.validation.Validator;
39 import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
40 import org.springframework.web.accept.ContentNegotiationManager;
41 import org.springframework.web.bind.annotation.RequestMapping;
42 import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
43 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
44 import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
45 import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
46 import org.springframework.web.servlet.resource.ResourceUrlProvider;
47 import org.thymeleaf.spring6.SpringTemplateEngine;
48 import org.thymeleaf.spring6.view.ThymeleafViewResolver;
49 import org.thymeleaf.templatemode.TemplateMode;
50 import org.thymeleaf.templateresolver.ITemplateResolver;
51 import org.thymeleaf.templateresolver.WebApplicationTemplateResolver;
52 import org.thymeleaf.web.IWebApplication;
53 import org.thymeleaf.web.servlet.JakartaServletWebApplication;
54
55
56
57
58
59 @Configuration
60 @Order(value = Ordered.LOWEST_PRECEDENCE)
61 public class WebMvcConfiguration extends WebMvcConfigurationSupport {
62
63 private static final Logger LOG = LoggerFactory.getLogger(WebMvcConfiguration.class);
64
65 private static final String MESSAGE_SOURCE = "/WEB-INF/i18n/messages";
66 private static final String VIEWS = "/WEB-INF/views/";
67
68 private static final String RESOURCES_LOCATION = "/resources/";
69 private static final String RESOURCES_HANDLER = RESOURCES_LOCATION + "**";
70
71
72 private static IWebApplication application;
73
74 @Override
75 public RequestMappingHandlerMapping requestMappingHandlerMapping(ContentNegotiationManager mvcContentNegotiationManager, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
76
77 RequestMappingHandlerMapping rmhm = super.requestMappingHandlerMapping(mvcContentNegotiationManager, mvcConversionService, mvcResourceUrlProvider);
78 rmhm.setUseSuffixPatternMatch(false);
79 rmhm.setUseTrailingSlashMatch(false);
80
81 return rmhm;
82 }
83
84 @Bean(name = "messageSource")
85 public MessageSource messageSource() {
86 ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
87 messageSource.setBasename(MESSAGE_SOURCE);
88 messageSource.setCacheSeconds(5);
89 return messageSource;
90 }
91
92 @Bean
93 @Description("Thymeleaf Template Resolver")
94 public ITemplateResolver templateResolver() {
95
96
97 application = JakartaServletWebApplication.buildApplication(getServletContext());
98
99
100 final WebApplicationTemplateResolver templateResolver
101 = new WebApplicationTemplateResolver(application);
102
103
104 templateResolver.setTemplateMode(TemplateMode.HTML);
105
106 templateResolver.setPrefix(VIEWS);
107 templateResolver.setSuffix(".html");
108
109
110 templateResolver.setCacheTTLMs(3600000L);
111
112
113
114 templateResolver.setCacheable(true);
115
116 return templateResolver;
117 }
118
119 @Bean
120 @Description("Thymeleaf Template Engine")
121 public SpringTemplateEngine templateEngine() {
122 SpringTemplateEngine templateEngine = new SpringTemplateEngine();
123 templateEngine.setTemplateResolver(templateResolver());
124 templateEngine.setTemplateEngineMessageSource(messageSource());
125 return templateEngine;
126 }
127
128 @Bean
129 @Description("Thymeleaf View Resolver")
130 public ThymeleafViewResolver viewResolver() {
131 ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
132 viewResolver.setTemplateEngine(templateEngine());
133 viewResolver.setCharacterEncoding("UTF-8");
134 viewResolver.setOrder(1);
135 return viewResolver;
136 }
137
138 @Override
139 public Validator getValidator() {
140 LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
141 validator.setValidationMessageSource(messageSource());
142 return validator;
143 }
144
145 @Override
146 public void addResourceHandlers(ResourceHandlerRegistry registry) {
147 registry.addResourceHandler(RESOURCES_HANDLER)
148 .addResourceLocations(RESOURCES_LOCATION)
149
150
151 .setCachePeriod(604800)
152 .setCacheControl(CacheControl.maxAge(604800, TimeUnit.SECONDS));
153 }
154
155 @Override
156 public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
157 configurer.enable();
158 }
159
160
161
162
163
164 @Controller
165 static class FaviconController {
166
167 @RequestMapping("favicon.ico")
168 String favicon() {
169 return "forward:/resources/images/favicon.ico";
170 }
171 }
172
173 @Override
174 public void addFormatters(FormatterRegistry formatterRegistry) {
175 LOG.debug("Add converters.");
176
177
178
179
180
181
182
183
184
185
186
187
188 }
189
190 }