View Javadoc
1   /*
2    * Copyright 2018-2022 Medical Information Systems Research Group (https://medical.zcu.cz),
3    * Department of Computer Science and Engineering, University of West Bohemia.
4    * Address: Univerzitni 8, 306 14 Plzen, Czech Republic.
5    *
6    * Author Petr Vcelak (vcelak@kiv.zcu.cz).
7    *
8    * This file is part of MRECore project.
9    *
10   * MRECore is free software: you can redistribute it and/or modify
11   * it under the terms of the GNU General Public License as published by
12   * the Free Software Foundation, either version 3 of the License.
13   *
14   * MRECore is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17   * GNU General Public License for more details.
18   *
19   * You should have received a copy of the GNU General Public License
20   * along with MRECore. If not, see <http://www.gnu.org/licenses/>.
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   * @author Petr Vcelak (vcelak@kiv.zcu.cz)
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      // Web Application.
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          // Web Application.
97          application = JakartaServletWebApplication.buildApplication(getServletContext());
98  
99          // Templates will be resolved as application (ServletContext) resources
100         final WebApplicationTemplateResolver templateResolver
101                 = new WebApplicationTemplateResolver(application);
102 
103         // HTML is the default mode, but we will set it anyway for better understanding of code
104         templateResolver.setTemplateMode(TemplateMode.HTML);
105         // This will convert "home" to "/WEB-INF/templates/home.html"
106         templateResolver.setPrefix(VIEWS);
107         templateResolver.setSuffix(".html");
108 
109         // Set template cache TTL to 1 hour. If not set, entries would live in cache until expelled by LRU
110         templateResolver.setCacheTTLMs(3600000L);
111 
112         // Cache is set to true by default. Set to false if you want templates to
113         // be automatically updated when modified.
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                 // fix for IE not loading fonts after refresh, or after direct url input
150                 // https://connect.microsoft.com/IE/feedbackdetail/view/992569/font-face-not-working-with-internet-explorer-and-http-header-pragma-no-cache
151                 .setCachePeriod(604800) // 7 days
152                 .setCacheControl(CacheControl.maxAge(604800, TimeUnit.SECONDS));
153     }
154 
155     @Override
156     public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
157         configurer.enable();
158     }
159 
160     /**
161      * Handles favicon.ico requests assuring no <code>404 Not Found</code> error
162      * is returned.
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 //        formatterRegistry.addConverter(new OntClassToStringConverter());
178 //
179 //        formatterRegistry.addConverter(new PropertyToStringConverter());
180 //        formatterRegistry.addConverter(new StringToPropertyConverter());
181 //
182 //        formatterRegistry.addConverter(new StringToResourceConverter());
183 //        formatterRegistry.addConverter(new ResourceToStringConverter());
184 //
185 //        formatterRegistry.addConverter(new StringToResourceWrapperConverter());
186 //
187 //        formatterRegistry.addConverter(new IndividualToStringConverter());
188     }
189 
190 }