Spring Boot 整合视图层技术 Thymeleaf

news2024/11/15 19:59:16

大家好!我是今越。简单记录一下在 Spring Boot 框架中如何整合 Thymeleaf 及使用。

Thymeleaf 简介

Thymeleaf 是新一代 Java 模板引擎,它类似于 Velocity、FreeMarker 等传统 Java 模板引擎,但是与传统 Java 模板引擎不同的是,Thymeleaf 支持 HTML 原型。它既可以让前端工程师在浏览器中直接打开查看样式,也可以让后端工程师结合真实数据查看显示效果,同时,SpringBoot 提供了 Thymeleaf 自动化配置解决方案,因此在 SpringBoot 中使用 Thymeleaf 非常方便。

事实上, Thymeleaf 除了展示基本的 HTML ,进行页面渲染之外,也可以作为一个 HTML 片段进行渲染,例如我们在做邮件发送时,可以使用 Thymeleaf 作为邮件发送模板。另外,由于 Thymeleaf 模板后缀为 .html,可以直接被浏览器打开,因此,预览时非常方便。

整合 Spring Boot

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Thymeleaf 不仅仅能在 Spring Boot 中使用,也可以使用在其他地方,只不过 Spring Boot 针对 Thymeleaf 提供了一整套的自动化配置方案,这一套配置类的属性在 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties 中,部分源码如下:

@ConfigurationProperties(
    prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";
    private String suffix = ".html";
    private String mode = "HTML";
    private Charset encoding;
    private boolean cache;
    private Integer templateResolverOrder;
    private String[] viewNames;
    private String[] excludedViewNames;
    private boolean enableSpringElCompiler;
    private boolean renderHiddenMarkersBeforeCheckboxes;
    private boolean enabled;
    private final ThymeleafProperties.Servlet servlet;
    private final ThymeleafProperties.Reactive reactive;

    public ThymeleafProperties() {
        this.encoding = DEFAULT_ENCODING;
        this.cache = true;
        this.renderHiddenMarkersBeforeCheckboxes = false;
        this.enabled = true;
        this.servlet = new ThymeleafProperties.Servlet();
        this.reactive = new ThymeleafProperties.Reactive();
    }
    // ...
}

1)首先通过 @ConfigurationProperties 注解,将 application.properties 前缀为 spring.thymeleaf 的配置和这个类中的属性绑定。这些配置,如果开发者不自己提供,则使用默认的。

2)前三个 static 变量定义了默认的编码格式、视图解析器的前缀、后缀等。

3)从前三行配置中,可以看出来,Thymeleaf 模板的默认位置在 resources/templates 目录下,默认的后缀是 html

而我们刚刚提到的,Spring Boot 为 Thymeleaf 提供的自动化配置类,则是 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration ,部分源码如下:

@AutoConfiguration(
    after = {WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class}
)
@EnableConfigurationProperties({ThymeleafProperties.class})
@ConditionalOnClass({TemplateMode.class, SpringTemplateEngine.class})
@Import({ReactiveTemplateEngineConfiguration.class, DefaultTemplateEngineConfiguration.class})
public class ThymeleafAutoConfiguration {}

可以看到,在这个自动化配置类中,首先导入 ThymeleafProperties ,然后 @ConditionalOnClass 注解表示当在系统中存在 TemplateModeSpringTemplateEngine 类时,当前的自动化配置类才会生效,即只要项目中引入了 Thymeleaf 相关的依赖,这个配置就会生效。

这些默认的配置我们几乎不需要做任何更改就可以直接使用了。如果开发者有特殊需求,则可以在 application.properties 中配置以 spring.thymeleaf 开头的属性即可。

示例-基本用法

创建类和接口

public class User {
    private Integer id;
    private String name;
    private String address;
    // setter, getter
}
@Controller
public class UserController {
    @GetMapping("/index")
    public String index(Model model, HttpSession session) {
        List<User> userList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setId(i);
            user.setName("jackson - " + i);
            user.setAddress("Hangzhou - " + i);
            userList.add(user);
        }
        model.addAttribute("users", userList);
        return "index";
    }
}

IndexController 中返回逻辑视图名+数据,逻辑视图名为 index ,意思我们需要在 resources/templates 目录下提供一个名为 index.html 的 Thymeleaf 模板文件。

index.html 页面中渲染数据

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<table border="1">
    <tr>
        <td>编号</td>
        <td>姓名</td>
        <td>地址</td>
    </tr>
    <tr th:each="user : ${users}">
        <td th:text="${user.id}"></td>
        <td th:text="${user.name}"></td>
        <td th:text="${user.address}"></td>
    </tr>
</table>
</body>
</html>

在 Thymeleaf 中,通过 th:each 指令来遍历一个集合,数据的展示通过 th:text 指令来实现。

注意 index.html 最上面引入 thymeleaf 名称空间(最新版并无强制要求)

显示效果如下

示例-手动渲染

上面我们说的是返回一个 Thymeleaf 模板,我们也可以手动渲染 Thymeleaf 模板,这个一般在邮件发送时候有用,例如我在 resources/templates 目录下新建一个邮件模板 mail.html,如下:

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <p>hello 欢迎 <span th:text="${username}"></span>加入 XXX 集团,您的入职信息如下:</p>
    <table border="1">
        <tr>
            <td>职位</td>
            <td th:text="${position}"></td>
        </tr>
        <tr>
            <td>薪水</td>
            <td th:text="${salary}"></td>
        </tr>
    </table>
</body>
</html>

这一个 HTML 模板中,有几个变量,我们要将这个 HTML 模板渲染成一个 String 字符串,再把这个字符串通过邮件发送出去,那么如何手动渲染呢?

@SpringBootTest
class ThymeleafApplicationTests {
    @Autowired
    TemplateEngine templateEngine;
    @Test
    void contextLoads() {
        Context context = new Context();
        context.setVariable("username", "jackson");
        context.setVariable("position", "后端开发");
        context.setVariable("salary", "35000");
        String mail = templateEngine.process("mail", context);
        System.out.println(mail);
        // 省略邮件发送
    }
}

1、渲染时,我们需要首先注入一个 TemplateEngine 对象,这个对象就是在 Thymeleaf 的自动化配置类中配置的(即当我们引入 Thymeleaf 的依赖之后,这个实例就有了)。

2、然后,构造一个 Context 对象用来存放变量。

3、调用 process 方法进行渲染,该方法的返回值就是渲染后的 HTML 字符串,然后我们将这个字符串发送出去。

Thymeleaf 使用细节

标准表达式

定义接口

@Controller
public class UserController {
    @GetMapping("/index")
    public String index(Model model, HttpSession session) {
        session.setAttribute("name", "张三丰");
        List<User> userList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setId(i);
            user.setName("jackson - " + i);
            user.setAddress("Hangzhou - " + i);
            userList.add(user);
        }
        model.addAttribute("users", userList);
        User instance = new User();
        instance.setId(99);
        instance.setName("向往的今越");
        instance.setAddress("杭州");
        model.addAttribute("user", instance);
        return "index";
    }
}

简单表达式

1)${…}

直接使用 th:xx = "${}" 获取对象属性。

<td th:text="${user.id}"></td>
<td th:text="${user.name}"></td>
<td th:text="${user.address}"></td>

2)*{…}

可以像 ${...} 一样使用,也可以通过 th:object 获取对象,然后使用 th:xx = "*{}" 获取对象属性,这种简写风格极为清爽,推荐大家在实际项目中使用。

<td th:text="*{user.id}"></td>
<td th:text="*{user.name}"></td>
<td th:text="*{user.address}"></td>
<hr/>
<div th:object="${user}">
    <div th:text="*{address}"></div>
    <div th:text="*{name}"></div>
    <div th:text="*{id}"></div>
</div>

3)#{…}

通常的国际化属性:#{...} 用于获取国际化语言翻译值。

在 resources 目录下新建两个文件:messages.propertiesmessages_zh_CN.properties,内容如下:

messages.properties

message = hello jackson!

messages_zh_CN.properties

message = 你好,少年!

然后在 thymeleaf 中引用 message,系统会根据浏览器的语言环境显示不同的值:

<div th:text="#{message}"></div>

4)@{…}

引用绝对 URL

<script type="text/javascript" th:src="@{http://localhost:8080/hello.js}"></script>

等价于

<script type="text/javascript" src="http://localhost:8080/hello.js"></script>

上下文相关的 URL

首先在 application.properties 中配置 Spring Boot 的上下文,以便于测试:

server.servlet.context-path=/myapp

引用路径

<!--无论上下文名称是什么,都能正常解析-->
<script type="text/javascript" th:src="@{/hello.js}"></script>

等价于

<script type="text/javascript" src="/myapp/hello.js"></script>

相对 URL

这个相对是指相对于服务器的 URL

<script type="text/javascript" th:src="@{~/hello.js}"></script>

等价于

<script type="text/javascript" src="/hello.js"></script>

应用程序的上下文 /myapp 将被忽略。

协议相对 URL

<script type="text/javascript" th:src="@{//localhost:8080/hello.js}"></script>

等价于

<script type="text/javascript" src="//localhost:8080/hello.js"></script>

带参数的 URL

<script type="text/javascript" th:src="@{//localhost:8080/hello.js(name='jackson',age=18)}"></script>

等价于

<script type="text/javascript" src="//localhost:8080/hello.js?name=jackson&age=18"></script>

5)~{…}

片段表达式是 Thymeleaf 的特色之一,细粒度可以达到标签级别,这是 JSP 无法做到的。片段表达式拥有三种语法:

  • ~{ viewName } : 表示引入完整页面
  • ~{ viewName ::selector} : 表示在指定页面寻找片段,其中 selector 可为片段名、jquery 选择器等
  • ~{ ::selector} : 表示在当前页寻找

举例

在 resources/templates 目录下新建 my_fragment.html 文件,内容如下

<div th:fragment="github_link">
  <a href="https://github.com">github</a>
</div>
<div th:fragment="alibaba_link">
  <a href="https://alibaba.com">alibaba</a>
</div>

这里有两个 div,通过 th:fragment 来定义片段,两个 div 分别具有不同的名字。

然后在另外一个页面中引用该片段:

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <p>hello 欢迎 <span th:text="${username}"></span>加入 XXX 集团,您的入职信息如下:</p>
    <table border="1" th:fragment="aaa">
        <tr>
            <td>职位</td>
            <td th:text="${position}"></td>
        </tr>
        <tr>
            <td>薪水</td>
            <td th:text="${salary}"></td>
        </tr>
    </table>
    <hr/>
    <div th:replace="my_fragment.html"></div>
    <hr/>
    <div th:replace="~{my_fragment.html::github_link}"></div>
    <hr/>
    <div th:replace="~{::aaa}"></div>
</body>
</html>

通过 th:replace 来引用片段。第一个表示引用完整的 my_fragment.html 页面;第二个表示引用 my_fragment.html 中的名为 github_link 的片段;第三个表示引用当前页面名为 aaa 的片段,也就是上面那个 table。

字面量

这些是一些可以直接写在表达式中的字符,主要有如下几种:

  • 文本字面量:‘one text’, ‘Another one!’,…
  • 数字字面量:0, 34, 3.0, 12.3,…
  • 布尔字面量:true, false
  • Null字面量:null
  • 字面量标记:one, sometext, main,…

举例

<div th:text="'你好 thymeleaf动态模版引擎'"></div>
<div th:text="9"></div>
<div th:text="true"></div>
<!--没有写单引号,不能使用空格,逗号或者中文-->
<div th:text="jackson"></div>

如果文本是英文,并且不包含空格、逗号等字符,可以不用加单引号。

文本运算

文本可以使用 + 进行拼接

<div th:text="'hello ' + 'jackson'"></div>
<div th:text="'hello' + ${user.name}"></div>

如果字符串中包含变量,也可以使用另一种简单的方式,叫做字面量置换,用 | 代替 '...' + '...',如下:

<div th:text="|hello ${user.name}|"></div>
<div th:text="'hello' + ' ' + 'jackson and ' + |hello ${user.name}|"></div>

算术运算

算术运算有:+, -, *, /%

<div th:with="age=(99*99/99+99-1)">
    <div th:text="${age}"></div>
</div>

th:with 定义了一个局部变量 age,在其所在的 div 中可以使用该局部变量。

逻辑运算

二元运算符:and, or

布尔非(一元运算符):!, not

<div th:with="age=(99*99/99+99-1)">
    <div th:text="9 eq 9 and 8 ne 8"></div>
    <div th:text="9 eq 9 or 8 ne 8"></div>
    <div th:text="!(9 eq 9 or 8 ne 8)"></div>
    <div th:text="not(9 eq 9 or 8 ne 8)"></div>
</div>

比较运算

表达式里的值可以使用 >, <, >=<= 符号比较。==!= 运算符用于检查相等(或者不相等)。

注意 XML 规定 <> 标签不能用于属性值,所以应当把它们转义为 &lt; 和 &gt;。

如果不想转义,也可以使用别名:gt (>);lt (<);ge (>=);le (<=);not (!)。还有 eq (==), neq/ne (!=)。

举例

<div th:with="age=(99*99/99+99-1)">
    <div th:text="${age} eq 197"></div>
    <div th:text="${age} ne 197"></div>
    <div th:text="${age} ge 197"></div>
    <div th:text="${age} gt 197"></div>
    <div th:text="${age} le 197"></div>
    <div th:text="${age} lt 197"></div>
</div>

条件运算

类似于我们 Java 中的三目运算符

<div th:with="age=(99*99/99+99-1)">
    <!--省略冒号后面的部分,当计算结果为false时,将返回null-->
    <div th:text="(${age} ne 197)?'yes':'no'"></div>
</div>

其中,: 后面的部分可以省略,如果省略了,又同时计算结果为 false 时,将返回 null。

内置对象

基本内置对象:

  • #ctx:上下文对象
  • #vars: 上下文变量
  • #locale:上下文区域设置
  • #request:(仅在 Web 上下文中)HttpServletRequest 对象
  • #response:(仅在 Web 上下文中)HttpServletResponse 对象
  • #session:(仅在 Web 上下文中)HttpSession 对象
  • #servletContext:(仅在 Web 上下文中)ServletContext 对象

在页面可以访问到上面这些内置对象,举例:

<div th:text="${#session.getAttribute('name')}"></div>

实用内置对象:

  • #execInfo:有关正在处理的模板的信息
  • #messages:在变量表达式中获取外部化消息的方法,与使用 #{…} 语法获得的方式相同。
  • #uris:转义URL / URI部分的方法
  • #conversions:执行配置的转换服务(如果有)的方法
  • #dates:java.util.Date 对象的方法:格式化,组件提取等
  • #calendars:类似于 #dates 但是 java.util.Calendar 对象
  • #numbers:用于格式化数字对象的方法
  • #strings:String 对象的方法:contains,startsWith,prepending / appending 等
  • #objects:一般对象的方法
  • #bools:布尔评估的方法
  • #arrays:数组方法
  • #lists:列表的方法
  • #sets:集合的方法
  • #maps:地图方法
  • #aggregates:在数组或集合上创建聚合的方法
  • #ids:处理可能重复的id属性的方法(例如,作为迭代的结果)

这是一些内置对象以及工具方法,使用方式也都比较容易,如果使用的是 IntelliJ IDEA,都会自动提示对象中的方法,很方便。

举例

<div th:text="${#lists.size(users)}"></div>
<div th:text="${#arrays.length(users)}"></div>
<div th:text="${#execInfo.getProcessedTemplateName()}"></div>

设置属性值

这个是给 HTML 元素设置属性值。可以一次设置多个,多个之间用 , 分隔开。

举例

<img th:attr="src=@{/1.png},title=${user.name},alt=${user.name}">

会被渲染成

<img src="/myapp/1.png" title="向往的今越" alt="向往的今越">

当然这种设置方法不太美观,可读性也不好。

Thymeleaf 还支持在每一个原生的 HTML 属性前加上 th: 前缀的方式来使用动态值,像下面这样:

<img th:src="@{/1.png}" th:alt="${user.name}" th:title="${user.name}">

这种写法看起来更清晰一些,渲染效果和前面一致。

上面案例中的 alt 和 title 则是两个特殊的属性,可以一次性设置,像下面这样:

<img th:src="@{/1.png}" th:alt-title="${user.name}">

遍历

数组/集合/Map/Enumeration/Iterator 等的遍历也算是一个非常常见的需求,Thymeleaf 中通过 th:each 来实现遍历。

<table border="1">
    <tr th:each="u : ${users}">
        <td th:text="${u.name}"></td>
        <td th:text="${u.address}"></td>
    </tr>
</table>

users 是要遍历的集合/数组,u 则是集合中的单个元素。

遍历的时候,我们可能需要获取遍历的状态,Thymeleaf 也对此提供了支持:

  • index:当前的遍历索引,从 0 开始
  • count:当前的遍历索引,从 1 开始
  • size:被遍历变量里的元素数量
  • current:每次遍历的遍历变量
  • even/odd:当前的遍历是偶数次还是奇数次
  • first:当前是否为首次遍历
  • last:当前是否为最后一次遍历

u 后面的 state 表示遍历状态,通过遍历状态可以引用上面的属性。

<table border="1">
    <tr th:each="u,state : ${users}">
        <td th:text="${u.name}"></td>
        <td th:text="${u.address}"></td>
        <td th:text="${state.index}"></td>
        <td th:text="${state.count}"></td>
        <td th:text="${state.size}"></td>
        <td th:text="${state.current}"></td>
        <td th:text="${state.even}"></td>
        <td th:text="${state.odd}"></td>
        <td th:text="${state.first}"></td>
        <td th:text="${state.last}"></td>
    </tr>
</table>

分支语句

只显示奇数次的遍历,可以使用 th:if,如下:

<table border="1">
    <tr th:each="u,state : ${users}" th:if="${state.odd}">
        <td th:text="${u.name}"></td>
        <td th:text="${u.address}"></td>
        <td th:text="${state.index}"></td>
        <td th:text="${state.count}"></td>
        <td th:text="${state.size}"></td>
        <td th:text="${state.current}"></td>
        <td th:text="${state.even}"></td>
        <td th:text="${state.odd}"></td>
        <td th:text="${state.first}"></td>
        <td th:text="${state.last}"></td>
    </tr>
</table>

th:if 不仅仅只接受布尔值,也接受其他类型的值,例如如下值都会判定为 true:

  • 如果值是布尔值,并且为 true

  • 如果值是数字,并且不为 0

  • 如果值是字符,并且不为 0

  • 如果值是字符串,并且不为 “false”, “off” 或者 “no”

  • 如果值不是布尔值,数字,字符或者字符串

但是,如果值为 null,th:if 会求值为 false


th:unless 的判定条件则与 th:if 完全相反。

<table border="1">
    <tr th:each="u,state : ${users}" th:unless="${state.odd}">
        <td th:text="${u.name}"></td>
        <td th:text="${u.address}"></td>
        <td th:text="${state.index}"></td>
        <td th:text="${state.count}"></td>
        <td th:text="${state.size}"></td>
        <td th:text="${state.current}"></td>
        <td th:text="${state.even}"></td>
        <td th:text="${state.odd}"></td>
        <td th:text="${state.first}"></td>
        <td th:text="${state.last}"></td>
    </tr>
</table>

这个显示效果则与上面的完全相反。


当可能性比较多的时候,也可以使用 switch:

<table border="1">
    <tr th:each="u,state : ${users}">
        <td th:text="${u.name}"></td>
        <td th:text="${u.address}"></td>
        <td th:text="${state.index}"></td>
        <td th:text="${state.count}"></td>
        <td th:text="${state.size}"></td>
        <td th:text="${state.current}"></td>
        <td th:text="${state.even}"></td>
        <td th:text="${state.odd}"></td>
        <td th:text="${state.first}"></td>
        <td th:text="${state.last}"></td>
        <td th:switch="${state.odd}">
            <span th:case="true">odd</span>
            <span th:case="*">even</span>
        </td>
    </tr>
</table>

th:case="*" 则表示默认选项。

本地变量

使用 th:with 可以定义一个本地变量,参考简单表达式部分。

內联

我们可以使用属性将数据放入页面模版中,但是很多时候,内联的方式看起来更加直观一些,像下面这样:

<!--[[...]]对应于th:text 结果会是转义的html-->
<div>hello [[${user.name}]]</div>
<!--[(...)]对应于th:utext 它不会执行任何的html转义-->
<div>hello [(${user.name})]</div>

用内联的方式去做拼接也显得更加自然。

举例

<div th:with="str='hello <strong>jackson</strong>'">
    <div>[[${str}]]</div>
    <div>[(${str})]</div>
</div>

显示效果如下

不过内联方式有一个问题。我们使用 Thymeleaf 的一大优势在于不用动态渲染就可以直接在浏览器中看到显示效果,当我们使用属性配置的时候确实是这样,但是如果我们使用内联的方式,各种表达式就会直接展示在静态网页中。

也可以在 js 或者 css 中使用内联,以 js 为例,使用方式如下:

<!--js 中需要通过 th:inline="javascript" 开启内联-->
<script th:inline="javascript">
    var n = [[${user.name}]];
    console.log(n);
</script>

官方文档

Thymeleaf 官网:https://www.thymeleaf.org

唯有热爱可抵岁月漫长。我是今越,欢迎大家点赞、收藏和评论,感谢支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/710374.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

爆肝整理,App测试小技巧,全覆盖功能到性能测试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 app测试是使用手动…

ES查询[全网最全免费送付费内容]

ES查询 相关度搜索&#xff0c;需要计算评分 _score 相关度评分用于对搜索结果排序&#xff0c;评分越高则认为其结果和搜索的预期值相关度越高&#xff0c;即越符合搜索预期值。在7.x之前相关度评分默认使用TF/IDF算法计算而来&#xff0c;7.x之后默认为BM25。 源数据&…

Win 10 重装系统(PE方式)

前言&#xff1a; 最近这个笔记本&#xff08;ThinkPad E480&#xff0c;使用了四年左右&#xff09;用起来很卡&#xff0c;经常开机状态时&#xff0c;合上之后&#xff0c;再打开屏幕就卡死了&#xff0c;鼠标和键盘按了都没有反应&#xff0c;无奈之下只能强制按电源关机后…

SpringCloud——Nacos下载

文章目录 nacos简介nacos下载nacos的启动访问nacos nacos简介 Nacos&#xff08;全称为 “Naming and Configuration Service”&#xff09;是阿里巴巴开源的一个用于实现动态服务发现、服务配置和服务元数据管理的项目。它是一个分布式系统的服务基础设施&#xff0c;为云原生…

turtle画春联

import turtle #右边春联 turtle.penup() turtle.goto(100,150) turtle.pendown() turtle.color(red,red) turtle.begin_fill() turtle.forward(50) turtle.right(90) turtle.forward(400) turtle.right(90) turtle.forward(50) turtle.right(90) turtle.forward(400) turtle.e…

【大数据Hive】Hive 窗口函数使用详解

目录 一、前言 二、hive 窗口函数概述 2.1 聚合函数与窗口函数差别 2.1.1 创建一张表 2.1.2 加载数据到表中 2.1.3 sumgroup by普通常规聚合操作 2.1.4 sum窗口函数聚合操作 三、窗口函数 3.1 窗口函数语法 3.2 参数说明 3.2.1 Function(arg1,..., argn) 3.2.2 OV…

ElasticSearch 索引设计

ElasticSearch 索引设计 在MySQL中数据库设计非常重要&#xff0c;同样在ES中数据库设计也是非常重要的 概述 创建索引就像创建表结构一样&#xff0c;必须非常慎重的&#xff0c;索引如果创建不好后面会出现各种各样的问题 索引设计的重要性 索引创建后&#xff0c;索引的分片…

找工作第二弹——挑战CSS重难点一篇就够

目录 前言CSS知识点篇1. 选择器2. CSS三大特性三大特性计算权重 3. 显示模式显示模式转化 4. 解决高度塌陷问题5. 浮动浮动介绍为什么要清除浮动-解决高度塌陷问题清除浮动额外标签法&#xff08;W3C推荐做法&#xff09;给父亲添加overflow伪元素法双伪元素 6. BFC7. 定位子绝…

辉哥带你学hive第八讲

1.自定义函数 1.1 自定义函数类型 根据用户自定义函数类别分为以下三种&#xff1a; &#xff08;1&#xff09;UDF&#xff08;User-Defined-Function&#xff09; 一进一出。 &#xff08;2&#xff09;UDAF&#xff08;User-Defined Aggregation Function&#xff09; 用户…

【二叉树part08】| 235.二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

目录 &#x1f388;LeetCode235.二叉搜索树的最近公共祖先 &#x1f388;LeetCode701.二叉搜索树中的插入操作 &#x1f388;LeetCode450.删除二叉搜索树中的节点 &#x1f388;LeetCode235.二叉搜索树的最近公共祖先 链接&#xff1a;235.二叉搜索树的最近公共祖先 给定一个…

Maven(三)如何使用命令导出所有的组件和版本信息

命令如下&#xff1a; mvn dependency:tree | grep ":jar" | sed s/ //g | sed s/-//g | sed s/\\-//g | sed s/|//g | awk !x[$0]注意&#xff1a;以上命令需要在 Git Bash 中执行。 执行结果&#xff1a; 整理完毕&#xff0c;完结撒花~ &#x1f33b;

Background-2 盲注的讲解基础概述二

文章目录 一、基于报错的 SQL 盲注------构造 payload 让信息通过错误提示回显出来二、基于时间的 SQL 盲注----------延时注入总结 一、基于报错的 SQL 盲注------构造 payload 让信息通过错误提示回显出来 select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,fl…

最全,常用正则表达式-正则实战(汇总)测试/开发工程师必备...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 校验数字的表达式…

Cookie、Session、Token、JWT详细介绍

Cookie、Session、Token详细介绍 &#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&#x1f680;&…

Vue3的setup语法糖下的defineEmit、defineExpose、defineProps函数

Vue3的setup语法糖下的defineEmit、defineExpose、defineProps父子传值 setup语法糖 setup作为vue3的新增生命周期hooks&#xff0c;其替代了vue2的beforeCreate、created&#xff0c;注意setup的执行时间是位于beforeCreate之前&#xff0c;熟悉vue2的都知道&#xff0c;在b…

C++——详解类模板

纵有疾风起&#xff0c;人生不言弃。本文篇幅较长&#xff0c;如有错误请不吝赐教&#xff0c;感谢支持。 &#x1f4ac;文章目录 一.类模板①类模板的定义与实例化②类模板的实例化③类模板的具体化&#xff08;特化、特例化&#xff09;1️⃣完全具体化2️⃣部分具体化3️⃣…

xxl-job源码改造集成:适配opengauss数据、适配单点登录等

目录 一、摘要 二、集成方案 三、集成步骤 3.1 springboot集成xxl-job 3.2 适配高斯数据库(postgresql) 3.3 页面集成 3.4 登录集成 3.5 接口集成 四、部署 一、摘要 公司现在打算重构产品&#xff0c;将原来的quartz替换成xxl-job&#xff0c;主要因为quartz不能动态…

多通道分离与合并

1、分离 2、合并 Mat img imread("F:/testMap/plan.png");Mat imgs[3];split(img,imgs);//分离Mat img0,img1,img2;img0 imgs[0];img1 imgs[1]; img2 imgs[2];Mat img_H;merge(imgs,3,img_H);//合并vector<Mat> imgsV; imgsV.push_back(img0);imgsV.push_b…

5.8.3 TCP连接管理(一)TCP连接建立

5.8.3 TCP连接管理&#xff08;一&#xff09;TCP连接建立 我们知道TCP是面向连接的传输协议&#xff0c;在传输连接的建立和释放是每一次面向连接通信必不可少的过程&#xff0c;因此传输连接的管理使得传输连接的建立和释放的过程都能够正常的进行。 一、使用Wireshark查看…

UE4/5用GeneratedDynamicMeshActor网格细分静态网格体【用的是ue5建模模式的box,其他的没有作用】

目录 制作 逻辑&#xff1a; 效果&#xff1a; ​编辑 代码&#xff1a; 制作 前面和之前的流程一样&#xff0c;打开插件和继承GeneratedDynamicMeshActor创建一个蓝图&#xff1a; 逻辑&#xff1a; 两个函数对应了两种细分方法 上面的细分模式是&#xff1a;Loop细…