SpringBoot之web页面渲染(一)Thymeleaf

模板引擎

介绍

传统的页面开发过程中通常采用的HTML + JS技术,而现在大部分网站都采用标签化+ 模块化 的设计 。模板引擎其实就是根据这种方式,使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档在原有的HTML页面中来填充数据。最终达到渲染页面的目的。
说人话就是,把数据和页面整合在一起的技术。

常用的模板引擎

  1. Thymleaf
  2. FreeMarker
  3. Velocity

SpringBoot整合Thymeleaf

Thymeleaf视图介绍

Thymeleaf是适用于Web和独立环境的现代服务器端Java模板引擎。
Thymeleaf的主要目标是为您的开发工作流程带来优雅的自然模板 -HTML可以在浏览器中正确显示,也可以作为静态原型工作,从而可以在开发团队中加强协作。
Thymeleaf拥有适用于Spring Framework的模块,与您喜欢的工具的大量集成以及插入您自己的功能的能力,对于现代HTML5 JVM Web开发而言,Thymeleaf是理想的选择。
在SpringBoot中,SpringBoot对Thymeleaf提供了良好的支持,同时也提供了自动化配置,因此在SpringBoot中使用Thymeleaf非常快捷方便。

SpringBoot中使用Thymeleaf

  1. 在SpringBoot项目中引入Thymeleaf的依赖
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  1. 配置Thymeleaf
    SpringBoot为Thymeleaf提供了自动化配置类ThymeleafAutoConfiguration,可以看出相关的配置信息是从ThymeleafProperties类中获得的,进一步查看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";
    //省略
}

相关配置如下:

#是否开启缓存,默认为true
spring.thymeleaf.cache=false
#检查模板文件是否存在
spring.thymeleaf.check-template=true
#检查模本目录是否存在
spring.thymeleaf.check-template-location=true
#模板文件编码
spring.thymeleaf.encoding=UTF-8
#模板位置
spring.thymeleaf.prefix=classpath:/templates/
#模板文件后缀名
spring.thymeleaf.suffix=.html
#Content-type
spring.thymeleaf.servlet.content-type=text/html

Thymeleaf语法

需要注意的是:模版页面中的 html 上需要声明 Thymeleaf 的命名空间,具体代码如下:

<html xmlns:th="http://www.thymeleaf.org">

文本标签 th:text/th:utext

作用:用于文本内容的显示操作。

  1. th:text 进行文本替换 不会解析html
  2. th:utext 进行文本替换 会解析html

字符串拼接

作用:拼接字符串通过 + 或者 | 进行拼接

代码演示:

@RequestMapping("/th")
	public String th(Model model){
		model.addAttribute("a",1);
		model.addAttribute("b",2);
		return "/course/th";
	}
模板页面:<p th:text="${a}+${b}"></p>

结果页面:<p>3</p>

模板页面:<p th:text="|${a} ${b}|"></p>

结果页面:<p>1 2</p>
模板页面:<p th:text="${a} > ${b}"></p>

结果页面:<p>false</p> 

*{…}和 ${…}表达式

作用:正常情况下 *{…} 和 ${…}是一样的,但是 *{…} 一般和 th:object 进行一起使用来完成对象属性的简写。

具体使用:
name和age都是user对象的属性,具体使用如下代码

<div th:object="${user}" >
	<p th:text="*{name}"></p>
	<p th:text="*{age}"></p>
</div>

#{…}表达式

作用:用于国际化message.properties 属性读取

~{…}片段表达式

作用:这个一般和模版布局的语法一起使用,具体使用方式请看下面模版布局的教程。

@{…}链接网址表达式

作用:一般和 th:href、th:src进行结合使用,用于显示Web 应用中的URL链接。通过@{…}表达式Thymeleaf 可以帮助我们拼接上web应用访问的全路径,同时我们可以通过()进行参数的拼接。

代码演示:

<img th:src="@{/images/gtvglogo.png}"  />

模板页面:<a th:href="@{/product/comments(prodId=${prod.id})}" >查看</a>
结果页面:<a href="/sbe/product/comments?prodId=2">查看</a>

条件判断 th:if/th:unless

  1. th:if 当条件为true则显示。
  2. th:unless 当条件为false 则显示。

代码演示:

模板页面:<p th:if="${flag}">if判断</p>
结果页面:<p>if判断</p>

switch

作用:th:switch 我们可以通过switch来完成类似的条件表达式的操作。

代码演示:

<div th:switch="${user.name}">
	  <p th:case="'ljk'">User is  ljk</p>
	  <p th:case="ljk1">User is ljk1</p>
</div>

for循环

作用:th:each 遍历集合。 迭代对象可以是java.util.List,java.util.Map,数组等数据类型;

代码演示:

<table>
   <thead>
     <tr>
       <th>用户名称</th>
       <th>用户年龄</th>
     </tr>
   </thead>
   <tbody>
     <tr th:each="user : ${userList}" th:class="${userStat.odd}? 'odd'">
       <td th:text="${user.name}">Onions</td>
       <td th:text="${user.age}">2.41</td>
     </tr>
   </tbody>
</table>

结果页面:
在这里插入图片描述
可以通过便利的变量名+Stat 来获取索引是否是第一个或最后一个等。便利的变量名+Stat称作状态变量,其属性有:

  • index:当前迭代对象的迭代索引,从0开始,这是索引属性;
  • count:当前迭代对象的迭代索引,从1开始,这个是统计属性;
  • size:迭代变量元素的总量,这是被迭代对象的大小属性;
  • current:当前迭代变量;
  • even/odd:布尔值,当前循环是否是偶数/奇数(从0开始计算);
  • first:布尔值,当前循环是否是第一个;
  • last:布尔值,当前循环是否是最后一个

th:href

作用:用于声明在a 标签上的href属性的链接 该语法会和@{…} 表达式一起使用。

代码演示:

模板页面:<a href="../home.html" th:href="@{/}">返回首页</a>
结果页面:<a href="/sbe/">返回首页</a>

th:class

作用:用于声明在标签上class 属性信息。

代码演示:

模板页面:<p th:class=" 'even'? 'even' : 'odd'" th:text=" 'even'? 'even' : 'odd'"></p>

结果页面:<p class="even">even</p>

th:attr

作用:用于声明html中或自定义属性信息。

代码演示:

模板页面:<img  th:attr="src=@{/images/gtvglogo.png}" />

结果页面:<img src="/sbe/images/gtvglogo.png">

th:value

作用:用于声明html中value属性信息。

代码演示:

模板页面:<input type="text" th:value="${name}" />

结果页面:<input type="text" value="ljk">

th:action

作用:用于声明html from标签中action属性信息。

代码演示:

模板页面
<form action="subscribe.html" th:action="@{/subscribe}">
		<input type="text" name="name" value="abc"/>
</form>

结果页面:
<form action="/sbe/subscribe">
		<input type="text" name="name" value="abc">
</form>

th:id

作用:用于声明htm id属性信息。

代码演示:

模板页面:<p th:id="${id}"></p>

结果页面:<p id="123"></p>

th:inline

作用:用于内联操作,详情见下面内敛介绍。

th:onclick

作用:用于声明htm 中的onclick事件。

th:selected

作用:用于声明htm 中的selected属性信息。

代码演示:

模板页面:
<select>
	<option name="sex"></option>
	<option th:selected="1 == ${sex}"></option>
	<option th:selected="0 == ${sex}"></option>
</select>

结果页面:
<select>
<option name="sex"></option>
	<option selected="selected"></option>
	<option></option>
</select>

th:src

作用:用于声明htm 中的img中src属性信息。

th:style

作用:用于声明htm中的标签 css的样式信息。

代码演示:

模板页面:<p th:style="'display:' + @{(${isShow} ? 'none' : 'block')} + ''"></p>

结果页面:<p style="display:none"></p>

th:with

作用:用于thymeleaf 模版页面中局部变量定义的使用。

代码演示:

模板页面:
<p th:with="df='dd/MMM/yyyy HH:mm'">
  		Today is: <span th:text="${#dates.format(today,df)}">13 February 2011</span>
</p>

结果页面:
<span>02/六月/2019 06:52</span>

Elvis运算符

作用:Elvis运算可以理解成简单的判断是否为null的三元运算的简写,如果值为nullzhe显示默认值,如果不为null 则显示原有的值。

代码演示:

<!-- 如果后台传过来的age的值为 null-->
模板页面:<p>Age: <span th:text="${age}?: '年龄为nll'"></span></p>

结果页面:<p>Age: <span>年龄为nll</span></p>

三元表达式

作用:我们可以在thymeleaf 的语法中使用三元表达式 具体使用方法是在th:x 中通过 表达式?1选项:2选项。

代码演示:

模板页面:1、<p th:class=" 'even'? 'even' : 'odd'" th:text=" 'even'? 'even' : 'odd'"></p>
2、<p th:value="${name eq 'ljk' ? '帅哥':'丑男'}" th:text="${name eq 'ljk' ? '帅哥':'丑男'}"></p>

结果页面:1、<p class="even">even</p>
2、<p value="帅哥">帅哥</p>

条件表达式操作字符:

  1. gt:great than(大于)
  2. ge:great equal(大于等于)
  3. eq:equal(等于)
  4. lt:less than(小于)
  5. le:less equal(小于等于)
  6. ne:not equal(不等于)

No-Operation(_)什么都不做

作用:是Elvis运算符的一种特殊简写操作,当显示的值为null 是就什么都不做。

代码演示:

模板页面:<span th:text="${name} ?: _">no user authenticated</span>

结果页面:<span>no user authenticated</span>

内联

  1. 如何使用内联:可以通过 在父标签声明 th:inline=“text” 来开启内联操作。当然如果想整个页面使用可以直接声明在body上即可。具体使用方式如下面代码所示。

    代码演示:

模板页面:
<div th:inline="text">
<p>Hello, [[${user.name}]]!</p>
</div>

结果页面:
<div>
<p>Hello,zhuoqianmingyue!</p>
</div>

等同于th:text
<div>
<p th:text="Hello,+${user.name}"></p>
</div>
[[...]]对应于th:text,[(...)]对应于th:utext
  1. 禁用内联操作:可以通过在父标签或者本标签上声明th:inline="none"来禁用内联的操作,如下面代码所示:
模板页面:<p th:inline="none">A double array looks like this: [[1, 2, 3], [4, 5]]!</p>

结果页面:<p>A double array looks like this: [[1, 2, 3], [4, 5]]!</p>
  1. JavaScript内联
    如果我们想在JavaScript 中使用内联操作,需要在 script 标签上声明 th:inline=“javascript” 然后我们就可以 script 标签中使用内联操作了。具体使用方式如下面代码所示:
<script th:inline="javascript">
    var username = [[${user.name}]];
</script>
  1. CSS内联
    可以通过在 style 标签上声明 th:inline=“css” 来开启在css中使用内联的操作,具体操作方式如下:
<style th:inline="css">
    .[[${classname}]] {
      text-align: [[${align}]];
    }
</style>

模板布局

SpringBoot2.0 使用模版模版布局需要先引入 thymeleaf的 thymeleaf-layout-dialect依赖

<dependency>
    <groupId>nz.net.ultraq.thymeleaf</groupId>
    <artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>
通过 th:fragment 定义引用片段

1、首先:我们可以通过 th:fragment 来定义引用片段,然后可以在其他页面进行引用。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div th:fragment="copy">
        &copy; 2011 The Good Thymes Virtual Grocery
    </div>
</body>
</html>

2、通过 th:insert 和 ~{…}片段引用表达式 进行引入footer.html中定义的片段

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <div th:insert="~{footer :: copy}"></div>
</body>
</html>

3、结果页面

<div>
  <div>
      © 2011 The Good Thymes Virtual Grocery
  </div>
</div>

如果你觉得~{footer :: copy}写法比较麻烦可以采用简写的方式footer :: copy。

<div th:insert="footer :: copy"></div>
<div th:insert="~{footer :: copy}"></div>
通过id属性来声明片段

1、也可以通过在引用片段代码上声明id属性的方式进行片段的引用

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="copy-section" >
    &copy; 2011 The Good Thymes Virtual Grocery
</div>
</body>
</html>

2、引用页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div th:insert="~{footer :: #copy-section}"></div>
</body>
</html>

3、结果页面

<div>
<div id="copy-section">
    © 2011 The Good Thymes Virtual Grocery
</div>
</div>

footer :: #copy-section和~{footer :: #copy-section} 结果是一致的。

th:insert和th:replace(和th:include)之间的区别

三者的使用方法相同:

  • th:insert 是最简单的:他会将使用th:insert的标签 和引用片段的内容都显示出来
  • th:replace 插入引用片段的标签和内容
  • th:include类似于th:insert,只插入此片段的内容。
带参数的引用片段

看下面代码就懂了

1、定义引用片段代码模版页面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div th:fragment="frag (onevar,twovar)">
    <p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>
</body>
</html>

2、引用引用片段的模版页面:index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div th:insert="footer :: frag('a','b')"></div>
</body>
</html>

3、结果页面

<div>
<div>
    <p>a - b</p>
</div>
</div>

总结:th:insert=“footer ::frag (onevar=‘a’,twovar=‘b’)” 和th:insert=“footer :: frag(‘a’,‘b’)效果是相等的。还有另一种写法就是使用th:with th:insert=”::frag" th:with=“onevar=‘a’,twovar=‘b’”

删除模版片段

thymeleaf 为我们提供了 th:remove

<tr class="odd" th:remove="all">
    <td>Blue Lettuce</td>
    <td>9.55</td>
    <td>no</td>
    <td>
      <span>0</span> comment/s
    </td>
  </tr>
  <tr th:remove="all">
    <td>Mild Cinnamon</td>
    <td>1.99</td>
    <td>yes</td>
    <td>
      <span>3</span> comment/s
      <a href="comments.html">view</a>
    </td>
  </tr>

在模拟数据上声明th:remove=“all” 后在此通过url访问 没有了我们之前的模拟数据,但是直接查看该页面还是可以查看到我们的模拟数据的。

all属性中的这个值是什么意思?th:remove可以根据其价值以五种不同的方式表现:

  1. all:删除包含标记及其所有子标记。
  2. body:不要删除包含标记,但删除其所有子标记。
  3. tag:删除包含标记,但不删除其子项。
  4. all-but-first:删除除第一个之外的所有包含标记的子项。
  5. none: 没做什么。此值对于动态评估很有用。

Thymeleaf的预定义的工具对象

dates

介绍:处理日期数据 生成,转换,获取日期的具体天数 年数。

format操作
模板页面:<span th:text="${#dates.format(date)}">4564546</span>

结果页面:<span>2019年5月30日 上午10时03分24秒 </span>
获取日期属性操作
date为后台传入的时间
模板页面:<p th:text="${#dates.day(date)} "></p>

结果页面:<p>30</p>

取出时间的方法介绍如下:

  1. day 当月的某一天
  2. month 哪一月(数字)
  3. monthName 哪一月(汉字)
  4. monthNameShort 哪一月(汉字)
  5. year 哪一年(数字)
  6. dayOfWeek 星期几(数字)
  7. dayOfWeekName 星期几(汉字)
  8. dayOfWeekNameShort 星期几(汉字)
  9. hour 小时
  10. minute 分钟
  11. millisecond 毫秒

numbers

处理数字数据的转换。包括:

  • 对不够位数的数字进行补0(formatInteger )
模板代码:<p th:text="${#numbers.formatInteger('123',4)}"></p>

结果页面:<p>0123</p>
  • 设置千位分隔符(formatInteger)
模板代码:<p th:text="${#numbers.formatInteger('1000',6,'POINT')}"></p>

结果页面:<p>001.000</p>
  • 精确小数点(formatDecimal )
模板代码:<p th:text="${#numbers.formatDecimal('1000.123',5,'POINT',2,'COMMA')}"></p>

结果页面:<p>01.000,12</p>
  • 钱显示符号操作
模板代码:<p th:text="${#numbers.formatCurrency('1000')}"></p>

结果页面:<p>¥1,000.00</p>
  • 设置百分号(formatPercent )
模板代码:<p th:text="${#numbers.formatPercent('0.2',2, 4)}"></p>

结果页面:<p>20.0000%</p>
  • 生成数组(sequence )
模板页面:
<div th:each="num : ${#numbers.sequence(0,4)}" >
          <p th:text="${num}"></p>
</div>

结果页面:
<div><p>0</p></div>
<div><p>1</p></div> 
<div><p>2</p></div>
<div><p>3</p></div>
<div><p>4</p></div>

strings

处理String的相关操作,包括:

  • 字符串转换(toString)
<p th:text="${#strings.toString(object)}"></p>
  • 检查字符串是否为空(isEmpty)
判断字符串是否为空
<p th:text="${#strings.isEmpty(name)}"></p>
判断集合是否为空
<p th:text="${#strings.listIsEmpty(nameList)}"></p>
  • 字符串是为空替换操作(defaultString)
<p th:text="${#strings.defaultString(text,'该值为null')}"></p>
  • 检查字符串中是否包含某个字符串(contains containsIgnoreCase)
判断字符串中是否含有字符
<p th:text="${#strings.contains('abcez','ez')}"></p>
判断字符串中是否含有字符(忽略大小写)
<p th:text="${#strings.containsIgnoreCase('abcEZ','ez')}"></p>

检查字符串是以片段开头还是结尾(startsWith endsWith)

<p th:text="${#strings.startsWith('Donabcez','Don')}"></p>

<p th:text="${#strings.endsWith('Donabcezn','n')}"></p> 
  • indexOf操作
<p th:text="${#strings.indexOf('abcefg','e')}"></p> 
  • 截取(substring substringAfter)
<p th:text="${#strings.substring('abcefg',3,5)}"></p>   
  • 替换(replace)
<p th:text="${#strings.replace('lasabce','las','ler')}"></p>
  • 追加(prepend append)
模板代码:<p th:text="${#strings.prepend('abc','012')}"></p>
结果页面:<p>012abc</p>

模板代码:<p th:text="${#strings.append('abc','456')}"></p>
结果页面:<p>abc456</p>
  • 变更大小写(toUpperCase toLowerCase)
<p th:text="${#strings.toUpperCase('abc')}"></p>

<p th:text="${#strings.toLowerCase('ABC')}"></p>  
  • length操作,获取字符串长度
<p th:text="${#strings.length('abc')}"></p>
  • 拆分和组合字符串(arrayJoin arraySplit)
${#strings.arrayJoin(namesArray,',')}
${#strings.arraySplit(namesStr,',')}
  • 去空格(trim)
<p th:text="${#strings.trim(' abc ')}"></p>
  • 缩写文本(abbreviate)
模板页面:<p th:text="${#strings.abbreviate('12345678910',10)}"></p>

结果页面:<p>1234567...</p>
  • 字符串连接(concat)
${#strings.concat(str)}

objects

处理Object对象的操作 包含obj不为空返回改值如果为空返回默认值(nullSafe)

<p th:text="${#objects.nullSafe(obj,'该对象为null')}"></p>

<p>该对象为null</p>

bools

判断对象是否为ture或者是否为false的操作。

  • 数字 1 为 ture , 0 为 false;
  • “on” 为 true, “off” 为false;
  • “true” 为true, "false"为 false;
isTrue操作
<p th:text="${#bools.isTrue(true)} "></p>

arrays

处理数组的相关操作的内置对象,包含:

  • 转换数组 toStringArray toIntegerArray,
<p th:text="${#arrays.toStringArray(object)} "></p>

<p>[Ljava.lang.String;@3cca655d</p>
  • 获取数组的长度(length )
  • 判断数组是否为空(isEmpty )
  • 是否包含某个元素(contains)
<p th:text="${#arrays.contains(array,1)} "></p>

<p>true</p>
  • 是否包含一批元素(containsAll)
<p th:text="${#arrays.containsAll(array,array2)} "></p>
 
<p>true</p>

lists

使用方式大致相同
处理 list 相关操作的内置对象,包括:

  • 计算长度(size)
  • 检查list是否为空(isEmpty)
  • 检查元素是否包含在list中(contains,containsAll)
  • 对给定list的副本排序(sort)

sets

使用方式大致相同
处理 set 相关操作的内置对象,包括:

  • 转换为Set(toSet)
  • 计算长度(size)
  • 检查set是否为空(isEmpty)
  • 检查元素是否包含在set中 (contains,containsAll)

maps

使用方式大致相同
处理 map相关操作的内置对象,包括:

  • 计算长度(size)
  • 检查map是否为空(isEmpty)
  • 检查映射中是否包含键或值(containsKey,containsAllKeys,containsValue)

aggregates

用户处理集合或者数组的一些统计操作,包括:

  • 求和(sum)
  • 求平均值(avg)
  • 处理包装类型或基本类型的数组或集合
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Spring Boot框架时,我们可以使用Thymeleaf模板引擎来渲染HTML页面Thymeleaf是一种面向服务器的模板引擎,它可以用来构建与Web标准兼容的HTML5页面。 在Spring Boot中,我们首先需要在pom.xml文件中添加Thymeleaf依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> ``` 在Spring Boot应用程序中,我们需要配置Thymeleaf的视图解析器。可以在application.properties文件中添加以下属性: ``` spring.thymeleaf.enabled=true spring.thymeleaf.cache=false ``` 可以看到,我们打开了Thymeleaf的缓存机制,以便更方便地测试HTML页面的更改。然后,我们需要在我们的Spring Boot应用程序中创建一个控制器,以便为HTML页面提供服务: ``` @Controller public class MyController { @GetMapping("/") public String index(Model model) { model.addAttribute("message", "Hello, Thymeleaf!"); return "index"; } } ``` 在上面的控制器中,我们使用@GetMapping注释来将应用程序映射到“/”路径。然后,我们将一个消息添加到Model中,以便将其传递给Thymeleaf视图。最后,我们返回视图名称“index”,这将是我们要渲染的HTML页面。 在Thymeleaf模板中,我们可以使用th:text属性来将消息添加到HTML页面中: ``` <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Hello, Thymeleaf</title> </head> <body> <h1 th:text="${message}">Hello, World!</h1> </body> </html> ``` 在上面的示例中,我们使用th:text属性来向页面添加消息。可以看到,我们使用了Thymeleaf的EL表达式来获取控制器中传递的消息。 使用了这些步骤后,当我们访问应用程序的根目录时,会渲染index.html页面,并将消息“Hello, Thymeleaf!”添加到页面中。这就是如何在Spring Boot应用程序中使用Thymeleaf模板引擎来渲染HTML页面

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值