Spring Boot与Apache Tiles的结合

9

我正在试图将我的Java应用程序迁移到Spring Boot。目前,我正在运行Spring MVC 3.2并使用Apache Tiles。当我迁移到Spring Boot时,我的控制器仍然可以正常调用,它们将视图传递给视图解析器,但是当Tiles去获取JSP文件时,事情就会出问题。 我收到的错误信息是:

13:48:46,387 TRACE org.springframework.web.servlet.handler.SimpleUrlHandlerMapping:127 - No handler mapping found for [/jsp/layout/layout.jsp]

有人成功地在Spring Boot中使用过Apache Tiles吗?有什么方法呢?

提前感谢您的任何想法!


更多细节:

@Bean
    public UrlBasedViewResolver viewResolver(){
        LOGGER.trace("Entering tiles configurer");
        UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
        viewResolver.setViewClass(TilesView.class);
        return viewResolver;
    }
    @Bean
    public TilesConfigurer tilesConfigurer(){
        LOGGER.trace("Entering tiles configurer");
        System.out.println("Entering tiles configurer");
        TilesConfigurer tilesConfigurer = new TilesConfigurer();
        String[] defs = {"/WEB-INF/tiles-defs.xml"};
        tilesConfigurer.setDefinitions(defs);
        return tilesConfigurer;
    }

控制器:


        @RequestMapping(value="/")
        public ModelAndView index(ModelAndView mav, HttpServletRequest request, HttpServletResponse resp,RedirectAttributes ra){
            LOGGER.trace("Arrived in Home Controller");
            mav.addObject("profile",appContext.getEnvironment().getActiveProfiles()[0]);
            mav.setViewName("home");
            return mav;
        }

tiles-definitions :

        <definition name="layout" template = "/jsp/layout/layout.jsp">
        </definition>
        <definition name="home" extends="layout">
            <put-attribute name="body" value = "/jsp/home.jsp" />
        </definition>

你的应用程序是WAR包吗(即是否有WEB-INF文件夹)?也许可以尝试将ViewResolverorder设置为低于默认值(这样就不会发生冲突了)?另外,P.S.(与使Tiles工作无关),你的控制器中没有使用HttpServlet*参数,而且要求使用它们是一种不好的风格,所以可以将它们删除。 - Dave Syer
我正在尝试使用由Spring Boot创建的基于JAR的应用程序,该应用程序使用嵌入式Tomcat服务器。感谢您提供有关HttpServlet参数的提示。我尝试在视图解析器上指定@Order(value = Ordered.LOWEST_PRECEDENCE-100)...但仍存在相同的问题。 - user3089280
如果你有一个JAR文件,那么你不应该有任何"src/main/webapp"(或者如果你有这个目录,它不会被包含在归档文件中)。尝试把所有内容放到"src/main/resources"中(也许使用"WEB-INF"就没有意义了)。我不知道Tiles是否知道如何从类路径加载资源,所以这可能是你面临的最大挑战。 - Dave Syer
1
嗯...我尝试将我的jsp放在src/main/resources中,但它没有找到它们。有趣的是,tiles能够成功读取src/main/webapp/WEB-INF中的tiles-def.xml。问题出现在Tiles获取jsp时。 - user3089280
@user3089280,你有解决办法吗?我遇到了一个类似布局的相同问题。 - Firdous Amir
显示剩余2条评论
5个回答

7
我也遇到了类似的问题,并通过上面各种答案的帮助解决了它。为了帮助将来可能遇到这个问题的其他人,我创建了一个简单的Maven项目在https://github.com/barryku/spring-boot-tiles,包含使用Spring Boot与Tiles所需的最小设置。以下是需要注意的几点:
  1. 需要tomcat-embed-jasper来呈现JSP页面
  2. 记得使用org.springframework.web.servlet.view.tiles3而不是tiles2包
  3. Spring的tiles3集成使用jstl,因此必须包含它
我逐步添加所需的文件,所以您可以查看https://github.com/barryku/spring-boot-tiles/commits/master中的提交历史,以更好地了解每个步骤添加了什么。

4

我有我的主要布局在/src/main/webapp/WEB-INF/layouts/layouts.xml中,示例条目如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
       "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

<tiles-definitions>

  <definition name="default" template="/WEB-INF/layouts/default.jspx">

    <put-attribute name="menu" value="/WEB-INF/views/menu.jspx"/>
    <put-attribute name="sidebar" value="/WEB-INF/views/sidebar.jspx"/>    
    <put-attribute name="header" value="/WEB-INF/views/header.jspx" />
    <put-attribute name="footer" value="/WEB-INF/views/footer.jspx" />
  </definition>

  <definition name="public" template="/WEB-INF/layouts/default.jspx"> 

    <put-attribute name="menu" value="/WEB-INF/views/menu.jspx"/>
    <put-attribute name="sidebar" value="/WEB-INF/views/sidebar.jspx"/> 
    <put-attribute name="header" value="/WEB-INF/views/header.jspx" />
    <put-attribute name="footer" value="/WEB-INF/views/footer.jspx" />
  </definition>

</tiles-definitions>

然后在/src/main/webapp/WEB-INF/views/views.xml中有更具体的瓷砖定义,样例条目如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN" "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
<tiles-definitions>

  <definition extends="default" name="index"> 
    <put-attribute name="body" value="/WEB-INF/views/index.jspx"/>
  </definition>

  <definition extends="public" name="login">
        <put-attribute name="sidebar" value=""></put-attribute>
        <put-attribute name="body" value="/WEB-INF/views/login.jspx"/>
    </definition>
</tiles-definitions>

然后您需要配置类:
@EnableWebMvc
@Configuration
public class RootMvcConfiguration extends WebMvcConfigurerAdapter {
    ...
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {

      registry.addViewController("/").setViewName("index");
      registry.addViewController("/login").setViewName("login");
    }
    ...
}

与瓷砖相关的类中的Bean将依赖于您是否想使用JSP或Thymeleaf。

对于JSP,您应该在其中包含以下内容:

 @Bean 
 public UrlBasedViewResolver tilesViewResolver(){

    UrlBasedViewResolver tilesViewResolver = new UrlBasedViewResolver();
    tilesViewResolver.setViewClass(TilesView.class);
    return tilesViewResolver;
}
 @Bean
 public TilesConfigurer tilesConfigurer(){ 

    String[] definitions = new String[] {
            "/WEB-INF/layouts/layouts.xml",
            "/WEB-INF/views/**/views.xml" /*Scans directories for Tiles configurations */
            };

    TilesConfigurer tilesConfigurer = new TilesConfigurer();
    tilesConfigurer.setDefinitions(definitions);
    return tilesConfigurer;

 }

如果您使用Thymeleaf,您应该有类似以下的内容:
@Bean
public MessageSource messageSource(){

    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasenames("classpath:META-INF/i18n/messages");
    messageSource.setFallbackToSystemLocale(false);
    return messageSource;
}
@Bean 
public ServletContextTemplateResolver templateResolver() {
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
        resolver.setPrefix("/WEB-INF/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML5");
        resolver.setOrder(2);
        resolver.setCacheable(false);            
        return resolver;
}

@Bean 
public SpringTemplateEngine templateEngine() throws Exception {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver());
        engine.setTemplateEngineMessageSource(messageSource());
        engine.addDialect(new TilesDialect());            
        engine.addDialect(new SpringSecurityDialect());            
        engine.afterPropertiesSet();
        return engine;
}
@Bean
public TilesConfigurer tilesConfigurer(){ 

    String[] definitions = new String[] {
            "/WEB-INF/layouts/layouts.xml",
            "/WEB-INF/views/**/views.xml" /*Scans directories for Tiles configurations */
            };

    ThymeleafTilesConfigurer tilesConfigurer = new ThymeleafTilesConfigurer();
    tilesConfigurer.setDefinitions(definitions);        
    return tilesConfigurer;

}

你可以扩展你的views.xml文件,将视图名称指向你的jsp或html文件,一个示例控制器可以如下所示:

@RequestMapping("/roles")
@Controller
public class RoleController {

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String show(@PathVariable("id") Integer id, Model uiModel) {
        uiModel.addAttribute("role", Role.findRole(id));
        uiModel.addAttribute("itemId", id);
        return "roles/show";
    }
}

如果你使用Maven,以下是一些示例库版本:
<properties>        
    <thymeleaf.version>2.0.19</thymeleaf.version>
    <thymeleaf.extras.version>2.0.0</thymeleaf.extras.version>         
    <thymeleaf.extras.security.version>2.0.0</thymeleaf.extras.security.version>
    <tiles.version>2.2.2</tiles.version>
</properties>
...
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>${jstl.version}</version>
    </dependency>

            <dependency>
        <groupId>org.apache.tiles</groupId>
        <artifactId>tiles-core</artifactId>
        <version>${tiles.version}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.tiles</groupId>
        <artifactId>tiles-jsp</artifactId>
        <version>${tiles.version}</version>
    </dependency>  

    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf</artifactId>
        <version>${thymeleaf.version}</version>
    </dependency>

    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring3</artifactId>
        <version>${thymeleaf.version}</version>
    </dependency>

    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity3</artifactId>
        <version>${thymeleaf.extras.security.version}</version>
    </dependency>

    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-tiles2</artifactId>
        <version>${thymeleaf.extras.version}</version>
    </dependency>

这个完美地运作了,简单而又完整的答案。谢谢! - cmikeb1

1
你需要将应用程序打包成war格式。Spring Boot、JSP和jar包装不太兼容。 同时,请确保在pom.xml中添加以下内容:
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
    </dependency>

0

你的定义应该是:

    <definition name="layout" template = "/WEB-INF/jsp/layout/layout.jsp">
    </definition>
    <definition name="home" extends="layout">
        <put-attribute name="body" value = "/WEB-INF/jsp/home.jsp" />
    </definition>

我曾经将我的jsp文件夹直接放在src/main/webapp下...我尝试将其移动到WEB-INF文件夹中,并根据您的建议更改定义。不幸的是,我仍然遇到相同的错误。 - user3089280
我编辑了我的答案,将引用改为/WEB-INF/...而不是/WEBINF/ **打字错误 - Prasad
你的tiles-def.xml文件在哪里?它的内容是什么? - Prasad
我的tiles-def.xml文件位于src/main/webapp/WEB-INF目录下。我有相当多的定义。您要我粘贴整个文件吗?它共有221行。 - user3089280
问题:1)你的控制器是如何定义的?2)你有哪些上下文文件?请展示它们。 - Prasad

0

我曾经遇到过与this question类似的问题。问题出在路径和前缀上。在Tiles定义中,我的路径是/WEB-INF/views/test.html,这是一个错误。下面是Spring应用程序(Thymeleaf 2、Tiles 2)的完整工作配置和示例文件。希望能对某些人有所帮助。

Beans

@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/test").setViewName("tiles/test");
    }

    @Bean
    public ServletContextTemplateResolver servletContextTemplateResolver() {
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML5");
        resolver.setCharacterEncoding("UTF-8");     
        return resolver;
    }   

    /**
     * Tiles view resolver
     * @param templateEngine
     * @return
     */
    @Bean
    public ViewResolver vr(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver th = new ThymeleafViewResolver();
        th.setTemplateEngine(templateEngine);
        th.setViewClass(ThymeleafTilesView.class);
        th.setCharacterEncoding("UTF-8");
        th.setOrder(Ordered.LOWEST_PRECEDENCE);
        return th;
    }

    /**
     * Basic view resolver
     * @param templateEngine
     * @return
     */
    @Bean
    public ViewResolver thymeleafViewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver vr = new ThymeleafViewResolver();
        vr.setTemplateEngine(templateEngine);
        vr.setCharacterEncoding("UTF-8");
        vr.setOrder(Ordered.HIGHEST_PRECEDENCE);
        // all tiles/* views will not be handled by this resolver;
        vr.setExcludedViewNames(new String[]{"tiles/*"});
        return vr;
    }   

    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        log.info(templateResolver);
        templateEngine.addDialect(new SpringSecurityDialect());
        templateEngine.addDialect(new TilesDialect());
        return templateEngine;
    }

    @Bean
    @SuppressWarnings("deprecation")
    public ThymeleafTilesConfigurer tilesConfigurer() {
        ThymeleafTilesConfigurer ttc = new ThymeleafTilesConfigurer();
        ttc.setDefinitions(new String[]{"/WEB-INF/tiles.xml"});
        return ttc;
    }   
}

瓷砖定义 - src/main/webapp/WEB-INF/tiles.xml

模板路径相对于templateResolver前缀,并且没有后缀。当我使用完整路径时,它不起作用,并出现异常,如下所示:

错误解析模板“/WEB-INF/views/layout.html”,模板可能不存在或无法被任何配置的模板解析器访问

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
          "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
          "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
<tiles-definitions>

  <definition name="baseLayout" template="layout">
  </definition>

  <definition name="tiles/test" extends="baseLayout">
    <put-attribute name="body" value="test"/>
    <put-attribute name="title" value="Test Page"/>
  </definition>
</tiles-definitions>

src/main/webapp/WEB-INF/views/layout.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:tiles="http://tiles.apache.org/tags-tiles">
<head>
    <title tiles:string="title">blah blah blah</title>
    <style type="text/css"></style>
</head>
<body>
    <div class="container">
        <div tiles:replace="body"></div>
    </div>
</body>
</html>

src/main/webapp/WEB-INF/views/test.html

2+2=<span xmlns:th="http://www.thymeleaf.org" th:text="2+2"></span>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接