Spring-Boot + Spring-MVC + Thymeleaf + Apache Tiles

前端 未结 2 1206
时光取名叫无心
时光取名叫无心 2020-12-10 20:06

I have an already existing client module with apache tiles and thymeleaf, what works well. I wanted to convert it to spring-boot and wanted to do it step by step, but I am r

2条回答
  •  猫巷女王i
    2020-12-10 20:53

    Okay guys,

    I got it and I hope it helps for other developers with similar problems.

    In POM I removed all Spring-Dependencies and I use only Spring-Starter-Dependencies like following snippet:

    ...
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
    
        
        
            org.apache.tiles
            tiles-template
            ${org.apache.tiles-version}
        
        
            org.apache.tiles
            tiles-servlet
            ${org.apache.tiles-version}
        
    
        
        
            org.thymeleaf.extras
            thymeleaf-extras-tiles2-spring4
            2.1.1.RELEASE
        
    
    ....
    

    In my Starter-Class I actived Thymeleaf Autoconfiguration again, my full class looks like follows. Be attended, I use two different servlets, one for REST, one for Thymeleaf.

    @Configuration
    @Import({ ServiceConfig.class, RestMvcConfig.class, WebMvcConfig.class })
    @EnableAutoConfiguration
    public class ApplicationClientMvc {
        public static void main(final String[] args) {
            SpringApplication.run(ApplicationClientMvc.class, args);
        }
    
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }
    
        @Bean
        public ServletRegistrationBean applicationDispatcherRegistration(final DispatcherServlet dispatcherServlet) {
            final ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet);
            registration.setName("applicationServlet");
            registration.addUrlMappings("/app/*");
            registration.setAsyncSupported(true);
            registration.setLoadOnStartup(1);
            registration.addInitParameter("contextConfigLocation", "a.c.b.c.m.w.WebMvcConfig");
            registration.setOrder(1);
            return registration;
        }
    
        @Bean
        public ServletRegistrationBean restDispatcherRegistration(final DispatcherServlet dispatcherServlet) {
            final ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet);
            registration.setName("restServlet");
            registration.addUrlMappings("/rest/*");
            registration.setAsyncSupported(true);
            registration.setLoadOnStartup(0);
            registration.addInitParameter("contextConfigLocation", "a.c.b.c.m.r.RestMvcConfig");
            registration.setOrder(0);
            return registration;
        }
    }
    

    ====

    My WebMVCConfig Class looks like follows, is in package ....mvc.rest:

    @Configuration
    @ComponentScan
    public class WebMvcConfig extends WebMvcAutoConfigurationAdapter {
    
        @Autowired public SpringTemplateEngine templateEngine;
    
        @Bean
        public ThymeleafTilesConfigurer tilesConfigurer() {
            final ThymeleafTilesConfigurer configurer = new ThymeleafTilesConfigurer();
            configurer.setDefinitions(ThymeleafAutoConfiguration.DEFAULT_PREFIX + "**/views.xml");
            return configurer;
        }
    
        @Bean
        public ThymeleafViewResolver thymeleafViewResolver() {
            final ThymeleafViewResolver resolver = new ThymeleafViewResolver();
            resolver.setViewClass(ThymeleafTilesView.class);
            resolver.setTemplateEngine(templateEngine);
            resolver.setCharacterEncoding(UTF_8);
            return resolver;
        }
    
        @Bean
        public TilesDialect tilesDialect() {
            return new TilesDialect();
        }
    
        //
    
        @Value("${server.session-timeout}") private Long sessionTimeOut;
    
        @Override
        public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
            configurer.setDefaultTimeout(sessionTimeOut * 1000L);
            configurer.registerCallableInterceptors(timeoutInterceptor());
        }
    
        @Bean
        public TimeoutCallableProcessingInterceptor timeoutInterceptor() {
            return new TimeoutCallableProcessingInterceptor();
        }
    
    }
    

    ===

    My RestConfig Class is pretty simple

    @Configuration
    @ComponentScan
    public class RestMvcConfig {}
    

    ===

    I moved all my html-files or thymeleaf-templates to template-folder under src/main/resources. Also in same folder you can put all client resources like images, js and css under the folder static. The folder static and templates are keywords and will be found by Spring-Boot automatically. There are no special configurations in application.properties what would be needed for thymeleaf and apache tiles.

    project structure

    ====

    That your application is able to find the resources, you can configure the path like follows:

    
    
    
    

    ===

    Folder java/src/webapp is no more needed!!!

    enter image description here

    ====

    If this helps for you, dont hesitate to vote ;-). If you need more information, just comment, I will try to answer within few days.

    ======

    SECOND STEP

    Okay, until now it only works under Eclipse. When I do executable jar, I get still an error. Maybe someone wants to help ;-)

    Stacktrace is :

    org.thymeleaf.exceptions.TemplateInputException: Error resolving template "/layout/login", template might not exist or might not be accessible by any of the configured Template Resolvers
        at org.thymeleaf.TemplateRepository.getTemplate(TemplateRepository.java:245)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1104)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060)
        at org.thymeleaf.extras.tiles2.renderer.ThymeleafAttributeRenderer.write(ThymeleafAttributeRenderer.java:155)
        at org.apache.tiles.renderer.impl.AbstractBaseAttributeRenderer.render(AbstractBaseAttributeRenderer.java:106)
        at org.thymeleaf.extras.tiles2.renderer.MetadataCleaningAttributeRendererWrapper.render(MetadataCleaningAttributeRendererWrapper.java:111)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:670)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:690)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:644)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:627)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:321)
        at org.thymeleaf.extras.tiles2.spring4.web.view.ThymeleafTilesView.render(ThymeleafTilesView.java:125)
        at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)
        at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
        at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
        at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:280)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
        at org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration$MetricsFilter.doFilterInternal(MetricFilterAutoConfiguration.java:90)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1736)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1695)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Unknown Source)
    

    The Structure of my JAR is like:

    enter image description here

    ======

    SOLUTION:

    I don't know exactly why, but additional I have to fix the url-paths for my templates, what works like it is in Eclipse, but not as executable jar. To get it run in both environments, I had to fix all template urls like follows, have a special look on attribute value:

    BEFORE:

    
        
        
    
    

    AFTER:

    
        
        
    
    

    Finally it works under Eclipse and as executable jars. Converting from normal Spring-Project to Spring-Boot Project was not really easy running, I hope it will help to other developers and I hope that post is worth to vote. ;-)

提交回复
热议问题