Thymeleaf (Java Spring):无法让 mvc.uri 工作

Eri*_*k T 5 java spring spring-mvc thymeleaf

我最近开始使用 Spring.io 和 Spring Boot 进行开发,并将 Thymeleaf 集成到我的 Web 应用程序中。我现在正在尝试使用mvc.uri实现反向路由,但我似乎无法使其工作。

这是HomeController显示我尝试反向路由的视图的 Web 控制器 ( ):

package com.twlab.billigalan.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;

@Controller
public class HomeController {

    @RequestMapping("/")
    @ResponseBody
    public ModelAndView home() {
        //String url = MvcUriComponentsBuilder.fromMappingName("HousingLoansController#main").build();
        ModelAndView model = new ModelAndView();
        //model.addObject("url",url);
        model.setViewName("pages/main/home");
        return model;
    }

    @RequestMapping("/server-error")
    public String error(HttpServletRequest request, Model model) {
        model.addAttribute("errorCode", request.getAttribute("javax.servlet.error.status_code"));
        Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
        String errorMessage = null;
        if (throwable != null) {
          errorMessage = throwable.getMessage();
        }
        model.addAttribute("errorMessage", errorMessage);
        return "pages/main/error.html";
    }
}
Run Code Online (Sandbox Code Playgroud)

这是视图:

<html
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="layouts/master.layout">
<head>
    <title>Billiga lån</title>
</head>
<body class="home">
    <div class="panel-body" layout:fragment="content">
        <a th:href="#{mvc.uri('HomeController#home').build()}">Test</a>
    </div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

这是主布局:

<!DOCTYPE html>
<html lang="sv"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:th="http://www.thymeleaf.org"
    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link href="http://cdn.jsdelivr.net/webjars/bootswatch-sandstone/3.3.2/css/bootstrap.min.css"
    th:href="@{/webjars/bootswatch-sandstone/3.3.2/css/bootstrap.min.css}"
    rel="stylesheet" media="screen" />
    <link rel="stylesheet" type="text/css" href="static/css/main.css" th:href="@{/css/main.css}" />
    <link rel="shortcut icon" href="static/favicon.ico" th:href="@{/favicon.ico}" />
    <title>Billiga lån</title>
</head>
<body>
<div id="wrapper" class="container">
    <div id="header" class="row">
        <div class="col-md-4">
            <a href="/" id="logo">Billiga lån</a>
            <span id="tagline">Billigaste lånen hittar du här!</span>
        </div>
        <div class="col-md-8"></div>
    </div>
    <!-- navbar -->
    <div class="navbar navbar-default" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed"
                    data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Visa meny</span> <span class="icon-bar"></span>
                    <span class="icon-bar"></span> <span class="icon-bar"></span>
                </button>
                <a href="/" class="navbar-brand frontpage"><i class="glyphicon glyphicon-home"></i></a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav navbar-left">
                    <li>
                        <a href="#">Låna pengar snabbt</a>
                    </li>
                    <li>
                        <a th:href="#{mvc.uri('HousingLoansController#main').build()}">Bolån</a>
                    </li>
                    <li>
                        <a href="#">Bil-lån</a>
                    </li>
                </ul>
            </div>
        </div>
    </div>
    <div id="main">
        <div id="sidebar" class="col-md-2 panel panel-default" layout:fragment="sidebar">
            <div class="panel-heading">Snabbstart</div>
            <div class="panel-body">
                <aside id="nav_menu-2" class="widget widget_nav_menu">
                    <div class="menu-sidomeny-container">
                        <ul id="menu-sidomeny" class="menu">
                            <li><a href="#">Låna pengar snabbt</a></li>
                            <li><a href="#">Lån med betalningsanmärkning</a></li>
                            <li><a th:uri="mvcUrl('HousingLoansController#main')">Bolån</a></li>
                            <li><a href="#">Bil-lån</a></li>
                        </ul>
                    </div>
                </aside>
            </div>
        </div>
        <div id="content" class="col-md-8">
            <div class="panel panel-default">
                <div class="panel-body" layout:fragment="content">

                </div>
                <!-- /panel-body -->
            </div>
            <!-- /panel -->
        </div>
        <!-- /#content -->
        <div id="right-sidebar" class="col-md-2 panel panel-default">
            <div class="panel-body" layout:fragment="right-sidebar">

            </div>
        </div>
    </div>
    <!-- /#main -->
</div>
<!-- /container -->
<div id="pre-footer">&nbsp;</div>
<!-- /pre-footer -->
<div id="footer"></div>
<!-- /footer -->
    <script src="http://cdn.jsdelivr.net/webjars/jquery/2.1.4/jquery.min.js"
        th:src="@{/webjars/jquery/2.1.4/jquery.min.js}"></script>
    <script src="http://cdn.jsdelivr.net/webjars/bootswatch-sandstone/3.3.2/js/bootstrap.min.js"
        th:src="@{/webjars/bootswatch-sandstone/3.3.2/js/bootstrap.min.js}"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

这是从布局 ( HousingLoansController)引用的控制器:

package com.twlab.billigalan.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HousingLoansController {

    @RequestMapping("/bolan")
    public ModelAndView main() {
        ModelAndView model = new ModelAndView();
        model.addObject("quickstart",null);
        model.setViewName("pages/housing-loans/housing-loans");
        return model;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是错误消息:

42) 2015-12-16 12:33:55.644 ERROR 8072 --- [nio-8080-exec-1] oaccC[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in带有路径 [] 的上下文抛出异常 [请求处理失败;嵌套异常是 org.thymeleaf.exceptions.TemplateProcessingException: 无法解析为表达式:"#{mvc.uri('HousingLoansController#main').build()}" (layouts/master.layout:42)] 与根本原因

org.thymeleaf.exceptions.TemplateProcessingException:无法解析为表达式:“#{mvc.uri('HousingLoansController#main').build()}”(布局/master.layout:42)在 org.thymeleaf.standard.expression .StandardExpressionParser.parseExpression(StandardExpressionParser.java:238) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.standard.expression.StandardExpressionParser.parseExpression(StandardExpressionParser.java:79) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.standard.expression.StandardExpressionParser.parseExpression(StandardExpressionParser.java:40) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4 .RELEASE] 在 org.thymeleaf.standard.processor.attr.AbstractStandardSingleAttributeModifierAttrProcessor.getTargetAttributeValue(AbstractStandardSingleAttributeModifierAttrProcessor.java:65) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.spring4.processor.attr.SpringHrefAttrProcessor.getTargetAttributeValue(SpringHrefAttrProcessor.java:68) ~[thymeleaf-spring4-2.1.4 .RELEASE.jar:2.1.4.RELEASE] at org.thymeleaf.processor.attr.AbstractSingleAttributeModifierAttrProcessor.getModifiedAttributeValues(AbstractSingleAttributeModifierAttrProcessor.java:59) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.1 .thymeleaf.processor.attr.AbstractAttributeModifierAttrProcessor.processAttribute(AbstractAttributeModifierAttrProcessor.java:62) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] at org.thymeleaf.processor.attr.AbstractProcessAttrProcessor.AbstractProcessAttrProcessor.java:62 java:87) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.processor.AbstractProcessor.process(AbstractProcessor.java:212) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.Node.applyNextProcessor(Node.java:1017) ~[thymeleaf-2.1.4.RELEASE.jar:2.1 .4.RELEASE] 在 org.thymeleaf.dom.Node.processNode(Node.java:972) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.NestableNode.computeNextChild (NestableNode.java:695) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[thymeleaf-2.1.4. RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.Node.processNode(Node.java:990) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf。 dom.NestableNode.computeNextChild(NestableNode.java:695) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[thymeleaf -2.1.4.RELEASE.jar:2.1。4.RELEASE] 在 org.thymeleaf.dom.Node.processNode(Node.java:990) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.NestableNode.computeNextChild( NestableNode.java:695) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[thymeleaf-2.1.4.RELEASE] .jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.Node.processNode(Node.java:990) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom .NestableNode.computeNextChild(NestableNode.java:695) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[thymeleaf- 2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.Node.processNode(Node.java:990) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在org.thymeleaf.dom.NestableNode。computeNextChild(NestableNode.java:695) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[thymeleaf-2.1.4 .RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.Node.processNode(Node.java:990) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf .dom.NestableNode.computeNextChild(NestableNode.java:695) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[ thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.Node.processNode(Node.java:990) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE ] 在 org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.NestableNode。doAdditionalProcess(NestableNode.java:668) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.Node.processNode(Node.java:990) ~[thymeleaf-2.1.4 .RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf .dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.Node.processNode(Node.java:990) ~[ thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE ] 在 org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.dom.Node.processNode(Node.java :第 990 章.4.RELEASE] 在 org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1155) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.TemplateEngine.process(TemplateEngine.java) :1060) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011) ~[thymeleaf-2.1.4.RELEASE.jar:2.1. 4.RELEASE] 在 org.thymeleaf.spring4.view.ThymeleafView.renderFragment(ThymeleafView.java:335) ~[thymeleaf-spring4-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.thymeleaf.spring4。 view.ThymeleafView.render(ThymeleafView.java:190) ~[thymeleaf-spring4-2.1.4.RELEASE.jar:2.1.4.RELEASE] 在 org.springframework.web.servlet.DispatcherServlet。render(DispatcherServlet.java:1244) ~[spring-webmvc-4.2.3.RELEASE.jar:4.2.3.RELEASE] 在 org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1027) ~[spring -webmvc-4.2.3.RELEASE.jar:4.2.3.RELEASE] 在 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:971) ~[spring-webmvc-4.2.3.RELEASE.jar: 4.2.3.RELEASE] 在 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) ~[spring-webmvc-4.2.3.RELEASE.jar:4.2.3.RELEASE] 在 org.springframework。 web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.2.3.RELEASE.jar:4.2.3.RELEASE] 在 org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java :861) ~[spring-webmvc-4.2.3.RELEASE.jar:4.2.3.RELEASE] 在 javax.servlet.http.HttpServlet。服务(HttpServlet.java:622) ~[tomcat-embed-core-8.0.28.jar:8.0.28] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc] -4.2.3.RELEASE.jar:4.2.3.RELEASE] 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[tomcat-embed-core-8.0.28.jar:8.0.28]在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) ~[tomcat-embed-core-8.0.28.jar:8.0.28] 在 org.apache.catalina.core.ApplicationFilterChain.doFilter( ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.28.jar:8.0.28] 在 org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed -websocket-8.0.28.jar:8.0.28] 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.28.jar:8.0.28] 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.28 .jar:8.0.28] 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework。 security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.FilterChainProxy $VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) ~[spring-security -web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.3. RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3 .RELEASE] 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework .security.web.authentication.AnonymousAuthenticationFilter。doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330 ) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) ~[spring-security- web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.3.RELEASE .jar:4.0.3.RELEASE] 在 org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3. RELEASE] 在 org.springframework。security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter .doFilter(AbstractAuthenticationProcessingFilter.java:205) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java: 330) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) ~[spring -security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0. 3.RELEASE.jar:4.0.3。RELEASE] 在 org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework。 web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.3.RELEASE.jar:4.2.3.RELEASE] 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy .java:330) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) ~[ spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.3.RELEASE .jar:4.2.3.RELEASE] 在 org.springframework.security.web。FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter .java:91) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[ spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) ~[spring-security -web-4.0.3.RELEASE.jar:4.0.3.RELEASE] 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.3.RELEASE.jar: 4.2.3.RELEASE] 在 org.springframework.security.web.FilterChainProxy$VirtualFilterCh

And*_*rew 4

看一下这里的例子#mvc是一个表达式对象,因此必须从 thymeleaf 表达式中访问,例如:

<a th:href="${#mvc.url('HomeController#home').build()}">Test</a>
Run Code Online (Sandbox Code Playgroud)

请注意,#mvc是在${...}符号中包含和引用的。

  • @ErikT `#mvc.uri` 似乎不存在(尽管 Thymeleaf 文档似乎建议它应该存在)。也许 `#mvc.url` 可以满足您的需求?请注意,您必须使用控制器的缩写,即。`#mvc.url('HC#home')` (2认同)