thymeleaf菜鸟教程_Spring MVC应用程序中的Thymeleaf模板布局,无扩展

news/2024/7/10 1:24:06 标签: java, python, spring, vue, html
htmledit_views">
thymeleaf菜鸟教程

thymeleaf菜鸟教程

在使用JSP / JSTL和Apache Tiles几年后,我开始为我的Spring MVC应用程序发现Thymeleaf。 Thymeleaf是一个非常出色的视图引擎,尽管目前缺乏良好的IntelliJ(投票:http: //youtrack.jetbrains.com/issue/IDEABKL-6713 )支持,但它简化并加快了开发速度(有Eclipse)插件)。 在学习如何使用Thymeleaf时,我研究了使用布局的不同可能性。

除了本机片段包含机制之外,还至少有两个选项可用于布局: Thymeleaf与Apache Tile的集成以及Thymeleaf Layout Dialect 。 两者似乎都可以正常工作,但是受到有关简单和自定义选项的评论的启发,我尝试了一下。 在这篇文章中,我将展示我创建了解决方案。

创建一个带有Thymeleaf支持的Spring MVC项目

为了快速入门,我在Thymeleaf 2.1支持下使用了Spring MVC原型。 我通过简单地调用原型创建了一个项目,然后将其导入到IntellJ中。

创建布局文件

在WEB-INF / views目录中,我创建了一个布局文件夹,在其中放置了第一个名为default.html的布局文件:$ {view}变量将包含@Controller返回的视图名称和$ {view}中的内容片段文件将放置在这里。

创建视图文件

我编辑了WEB-INF / views / homeNotSignedIn.html,然后按以下方式定义了内容片段:因此,唯一的更改是定义名为content的片段并删除重复的片段包含。 无需其他更改。 @Controller返回原始视图名称,就像以前一样:

html" title=java>java">@Controller
class HomeController {

 @RequestMapping(value = "/", method = RequestMethod.GET)
 String index(Principal principal) {
  return principal != null ? "home/homeSignedIn" : "home/homeNotSignedIn";
 }
}

我相应地改变了其他观点。

创建拦截器并与Spring MVC集成

为了完成“新布局框架”,我创建了一个处理程序拦截器来完成工作:

html" title=java>java">public class ThymeleafLayoutInterceptor extends HandlerInterceptorAdapter {

    private static final String DEFAULT_LAYOUT = "layouts/default";
    private static final String DEFAULT_VIEW_ATTRIBUTE_NAME = "view";

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (!modelAndView.hasView()) {
            return;
        }
        String originalViewName = modelAndView.getViewName();
        modelAndView.setViewName(DEFAULT_LAYOUT);
        modelAndView.addObject(DEFAULT_VIEW_ATTRIBUTE_NAME, originalViewName);
    }    
}

ThymeleafLayoutInterceptor获取从处理程序的方法返回的原始视图名称,并将其替换为布局名称(在WEB-INF / views / layouts / default.html中定义)。 原始视图作为视图变量放置在模型中,因此可以在布局文件中使用它。 我覆盖了postHandle方法,因为它是在呈现视图之前执行的。

添加拦截器很容易:

html" title=java>java">@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new ThymeleafLayoutInterceptor());
    }
}

这就是基本配置。 此后没有火箭。 转到localhost:8080后的结果。 这是我所期望的。 奇迹般有效。 因此,我尝试注册一个帐户以及提交表单后看到的内容:

html" title=java>java">500 returned for /signup with message Error resolving template "redirect:/", template might not exist or might not be accessible by any of the configured Template Resolvers

当然,重定向:/提交表单后。 我需要像这样修改拦截器:

html" title=java>java">public class ThymeleafLayoutInterceptor extends HandlerInterceptorAdapter {

    private static final String DEFAULT_LAYOUT = "layouts/default";
    private static final String DEFAULT_VIEW_ATTRIBUTE_NAME = "view";

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (!modelAndView.hasView()) {
            return;
        }
        String originalViewName = modelAndView.getViewName();
        if (isRedirectOrForward(originalViewName)) {
            return;
        }
        modelAndView.setViewName(DEFAULT_LAYOUT);
        modelAndView.addObject(DEFAULT_VIEW_ATTRIBUTE_NAME, originalViewName);
    } 
    private boolean isRedirectOrForward(String viewName) {
        return viewName.startsWith("redirect:") || viewName.startsWith("forward:");
    }   
}

它按预期工作。 但是我意识到我需要定义和附加布局,因为Signup和Signin之前(而不是在应用上述更改之后)使用了此布局。

创建其他布局

我创建了一个名为blank.html的新布局,并将其放置到WEB-INF / views / layouts文件夹中。 但是如何使用选择布局? 可能有很多方法可以做到这一点。 不过,最简单的方法之一是,只需添加一个名为layout的模型属性,即可从@Controller返回布局名称。 如果未给出布局,则使用默认布局,否则使用给定布局。 简单。 但是我想要一个更强大的解决方案。 所以我想也许我可以这样使用注释:

html" title=java>java">@Controller
class SigninController {

    @Layout(value = "layouts/blank")
    @RequestMapping(value = "signin")
    String signin() {
        return "signin/signin";
    }
}

对我来说,这听起来像是一个很好的解决方案。 所以我实现了它。

选择布局

我创建了一个方法级别@Layout批注,并将其放置在org.thymeleaf.html" title=spring>spring.support包中(与ThymeleafLayoutInterceptor一起):

html" title=java>java">package org.thymeleaf.html" title=spring>spring.support;

import html" title=java>java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Layout {
    String value() default "";
}

我将拦截器更改如下:

html" title=java>java">public class ThymeleafLayoutInterceptor extends HandlerInterceptorAdapter {

    private static final String DEFAULT_LAYOUT = "layouts/default";
    private static final String DEFAULT_VIEW_ATTRIBUTE_NAME = "view";

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (!modelAndView.hasView()) {
            return;
        }
        String originalViewName = modelAndView.getViewName();
        if (isRedirectOrForward(originalViewName)) {
            return;
        }
        String layoutName = getLayoutName(handler);
        modelAndView.setViewName(layoutName);
        modelAndView.addObject(DEFAULT_VIEW_ATTRIBUTE_NAME, originalViewName);
    }

    private boolean isRedirectOrForward(String viewName) {
        return viewName.startsWith("redirect:") || viewName.startsWith("forward:");
    }

    private String getLayoutName(Object handler) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Layout layout = handlerMethod.getMethodAnnotation(Layout.class);
        if (layout == null) {
            return DEFAULT_LAYOUT;
        } else {
            return layout.value();
        }
    }
}

现在,当使用@Layout注释对处理程序方法进行注释时,它将获得其value属性。 效果很好。 但是当我开始更改SignupController时,我意识到我需要注释这两种方法。 如果可以通过对@Controller类进行注释,将我的注释一次用于所有方法,那就更好了:

html" title=java>java">@Controller
@Layout(value = "layouts/blank")
class SignupController {

}

所以我做了。

最后的润色

首先,我更改了注释,以便可以将其定位为类型级别:

html" title=java>java">@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Layout {
    String value() default "";
}

和拦截器:

html" title=java>java">public class ThymeleafLayoutInterceptor extends HandlerInterceptorAdapter {

    private static final String DEFAULT_LAYOUT = "layouts/default";
    private static final String DEFAULT_VIEW_ATTRIBUTE_NAME = "view";

    private String defaultLayout = DEFAULT_LAYOUT;
    private String viewAttributeName = DEFAULT_VIEW_ATTRIBUTE_NAME;

    public void setDefaultLayout(String defaultLayout) {
        Assert.hasLength(defaultLayout);
        this.defaultLayout = defaultLayout;
    }

    public void setViewAttributeName(String viewAttributeName) {
        Assert.hasLength(defaultLayout);
        this.viewAttributeName = viewAttributeName;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (!modelAndView.hasView()) {
            return;
        }
        String originalViewName = modelAndView.getViewName();
        if (isRedirectOrForward(originalViewName)) {
            return;
        }
        String layoutName = getLayoutName(handler);
        modelAndView.setViewName(layoutName);
        modelAndView.addObject(this.viewAttributeName, originalViewName);
    }

    private boolean isRedirectOrForward(String viewName) {
        return viewName.startsWith("redirect:") || viewName.startsWith("forward:");
    }

    private String getLayoutName(Object handler) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Layout layout = getMethodOrTypeAnnotation(handlerMethod);
        if (layout == null) {
            return this.defaultLayout;
        } else {
            return layout.value();
        }
    }

    private Layout getMethodOrTypeAnnotation(HandlerMethod handlerMethod) {
        Layout layout = handlerMethod.getMethodAnnotation(Layout.class);
        if (layout == null) {
            return handlerMethod.getBeanType().getAnnotation(Layout.class);
        }
        return layout;
    }
}

如您所见,方法级别注释比类型级别注释更重要,它提供了一定的灵活性。 此外,我还添加了配置拦截器的可能性。 我认为,设置默认布局名称和视图属性名称可能很有用。

概要

提出的解决方案可能需要一些改进才能在生产中使用,但是它显示了我们如何轻松地构建模板布局而无需向项目中添加额外的库并仅利用Thymeleaf的核心功能。 请分享您对解决方案的评论和意见。

  • 请在GitHub上找到源代码: https : //github.com/kolorobot/thymeleaf-custom-layout
参考: Spring MVC应用程序中的Thymeleaf模板布局,在Codeleak.pl博客上没有JCG合作伙伴Rafal Borowiec的扩展。

翻译自: https://www.html" title=java>javacodegeeks.com/2013/11/thymeleaf-template-layouts-in-html" title=spring>spring-mvc-application-with-no-extensions.html

thymeleaf菜鸟教程


http://www.niftyadmin.cn/n/1708015.html

相关文章

matlab plot y 1,Matlab 画图(1)

如何把matlab画图窗口的背景颜色设置为白色?set(0,defaultfigurecolor,w)Fig1.摩擦系数变化曲线x0:0.2:1;y[0 0 0 0;0.58 0.31 0.18 0.08;0.83 0.56 0.36 0.19;1.14 0.89 0.62 0.30;1.56,1.23 0.78 0.36;2.08 1.52 0.99 0.49;]plot(x,y);Fig2.正弦图形x linspace(0…

Java学习笔记01(小白级别)

文章目录了解简单的DOS命令理解面向对象垃圾自动回收下载JDK下载集成开发环境eclipse环境配置第一个Java程序总的学习路线了解简单的DOS命令 窗口(Win)键 r,一起按下,输入cmd,可以打开dos界面 注意:在输入dos命令时,要使用英文输…

java安装_Java方法中的参数太多,第6部分:方法返回

java安装在当前的系列文章中,我正在致力于减少调用Java方法和构造函数所需的参数数量,到目前为止,我一直专注于直接影响参数本身的方法( 自定义类型, 参数对象, 构建器模式, 方法重载和方法命名)。 鉴于此&…

Eclipse安装及JDK配置环境变量(Win10)

win10系统 搜索环境变量配置,打开以下窗口 在系统变量里添加一个JAVA_HOME,值为JDK的安装路径,点击确定。 注意要提前安装jdk(傻瓜安装方法) 然后,在系统变量里面的path,添加jdk的bin路径。,注意是你安装jdk路径的…

Java学习笔记02(小白级别,数据类型,运算符)

文章目录1 Java基础语法Java关键字变量2 Java数据类型数据类型的转换3 各种运算i和i的区别(算数):短路与&&和&的区别(逻辑)三目运算符(?)位运算(有公式)1 Ja…

java安装_Java常见错误的十大列表(前100名!)

java安装前10名名单非常受欢迎,有趣并且内容丰富。 但是有很多! 如何选择合适的? 这是一个元前10名列表,可帮助您找到前10名的前10名列表。 在更令人讨厌的笔记上: SELECT TOP 10 mistake FROM source1 UNION ALL SEL…

GaussDB 普通用户通过函数来查看data_directory等目录参数值

默认情况下,普通用户是无法查看data_directory等目录相关参数,只能由超级用户来查看。 直接上函数语句: 必须以超级用户来创建 CREATE OR REPLACE function public.list_settings(OUT name text, OUT setting text, OUT unit text, OUT category text, …

php安装websocket扩展,使用swoole扩展phpwebsocket示例

代码如下:define(DEBUG, on);define("WEBPATH", str_replace("\\","/", __DIR__));require __DIR__ . /../libs/lib_config.php;class WebSocket extends Swoole\Network\Protocol\WebSocket{/*** 下线时,通知所有人*/function onClo…