Spring Boot 模板引擎Thymeleaf自定义标签
Thymeleafadmin 发布于:2022-05-09 10:19:39
阅读:loading
章接前文,自定义标签一直都是个人非常喜欢的一个技术点,它可以与实际需要相结合来简化我们功能的实现,本站就较多的JSP自定义标签的文章介绍,所以在本站建站初期在使用Thymeleaf的时候,也层花了一些时间专门用于它的自定义标签实现,但是也许是时间花的不够吧,一些知识细节属于云里雾里的,一些应用的深度不够,比如它的自定义标签如何获取内容体等,并未掌握,所以本篇所谓的自定义标签则是提供几个属性值处理的标签实现,详细实现过程如下。
package cn.chendd.base.thymeleaf.dialects;
import ...;
/**
* 自定义标签方言类
*
* @author chendd
* @date 2020/5/31 21:51
*/
@Component
public class DdDialect extends AbstractProcessorDialect {
/**
* 定义方言名称
*/
private static final String DIALECT_NAME = "Dd Dialect";
private static final String PREFIX = "dd";
protected DdDialect() {
super(DIALECT_NAME, PREFIX, StandardDialect.PROCESSOR_PRECEDENCE);
}
@Override
public Set<IProcessor> getProcessors(String dialectPrefix) {
Set<IProcessor> processors = Sets.newHashSet();
processors.add(new FormatProcessor(dialectPrefix));
processors.add(new ContentBodyProcessor(dialectPrefix));
processors.add(new FormatAttributeTagProcessor(TemplateMode.HTML , dialectPrefix));
return processors;
}
}
package cn.chendd.base.thymeleaf.processors;
import ...;
/**
* 格式化处理类
*
* @author chendd
* @date 2020/5/31 21:56
*/
public class FormatProcessor extends AbstractElementTagProcessor {
private static final String TAG_NAME = "format";//标签名
private static final int PRECEDENCE = 100000;//优先级
public FormatProcessor(String dialectPrefix) {
super(
TemplateMode.HTML, // 此处理器将仅应用于HTML模式
dialectPrefix, // 要应用于名称的匹配前缀
TAG_NAME, // 标签名称:匹配此名称的特定标签
true, // 将标签前缀应用于标签名称
null, // 无属性名称:将通过标签名称匹配
false, // 没有要应用于属性名称的前缀
PRECEDENCE); // 优先(内部方言自己的优先)
}
@Override
protected void doProcess(ITemplateContext context, IProcessableElementTag tag, IElementTagStructureHandler structure) {
String value = tag.getAttributeValue("value");
String type = tag.getAttributeValue("type");
FormatTypeEnum formatType = FormatTypeEnum.getInstance(type);
String result;
if (formatType == null || StringUtils.isEmpty(value)) {
result = new UndefinedFormat().format(value);
} else {
Class<? extends FormatType> formatTypeClazz = formatType.getClazz();
try {
result = ((FormatType) formatTypeClazz.newInstance()).format(value);
} catch (InstantiationException | IllegalAccessException e) {
throw new UnsupportedOperationException(e);
}
}
//替换原有标签的内容体
//structure.setBody(result , false);
//删除原有标签
//structure.removeTags();
structure.replaceWith(result , false);
}
}
package cn.chendd.base.thymeleaf.processors;
import ...;
/**
* 自定义属性
* @author chendd
* @date 2020/6/1 20:09
*/
public class FormatAttributeTagProcessor extends AbstractStandardExpressionAttributeTagProcessor {
public static final int PRECEDENCE = 1300;
public static final String ATTR_NAME = "raw-format";
public FormatAttributeTagProcessor(final TemplateMode templateMode, final String dialectPrefix) {
super(templateMode, dialectPrefix, ATTR_NAME, PRECEDENCE, true, (templateMode == TemplateMode.TEXT));
}
@Override
protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName, String attributeValue,
Object expressionResult, IElementTagStructureHandler structureHandler) {
if(expressionResult == null) {
structureHandler.removeTags();
return;
}
String result = RamFormat.Ram.getInstance(Double.valueOf(expressionResult.toString()));
structureHandler.replaceWith(result , false);
}
}
package cn.chendd.base.thymeleaf.processors;
import ...;
/**
* 内容体标签
*
* @author chendd
* @date 2022/6/4 11:17
*/
public class ContentBodyProcessor extends AbstractElementTagProcessor {
public static final int PRECEDENCE = 100000;
public static final String TAG_NAME = "content";
public ContentBodyProcessor(String dialectPrefix) {
super(
TemplateMode.HTML, // 此处理器将仅应用于HTML模式
dialectPrefix, // 要应用于名称的匹配前缀
TAG_NAME, // 标签名称:匹配此名称的特定标签
true, // 将标签前缀应用于标签名称
null, // 无属性名称:将通过标签名称匹配
false, // 没有要应用于属性名称的前缀
PRECEDENCE); // 优先(内部方言自己的优先)
}
@Override
protected void doProcess(ITemplateContext context, IProcessableElementTag tag, IElementTagStructureHandler structure) {
structure.setAttribute("hello" , "world");
ArrayList<Point> list = Lists.newArrayList(new Point(1, 2), new Point(3, 4));
structure.setLocalVariable(tag.getAttribute("var").getValue() , list);
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:dd="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Thymeleaf简单使用</title>
</head>
<body>
<fieldset>
<legend>自定义标签(格式化)</legend>
<h3>千分位金额:<dd:format th:type="amount" th:value="'5201314'">出生时间</dd:format></h3>
<h3>时间范围:<dd:format th:type="datetime" th:value="'2021-07-09 11:18:00'">出生时间</dd:format></h3>
<h3>磁盘大小:<dd:format th:type="ram" th:value="'5201314'">出生时间</dd:format></h3>
<h3>百分比:<dd:format th:type="percentage" th:value="'3.1414926'">出生时间</dd:format></h3>
<h3>undefined:<dd:format th:type="undefined" th:value="'undefined原样输出'">undefined</dd:format></h3>
</fieldset>
<fieldset>
<legend>自定义属性</legend>
<h3>标签使用方式:<th:block dd:raw-format="'5201314'">标签使用</th:block></h3>
<h3>属性使用方式:<th:block data-dd-raw-format="'5201314'">属性使用</th:block></h3>
</fieldset>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:dd="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Thymeleaf简单使用</title>
</head>
<body>
<dd:content var="list" sql="select 1 x , 2 y union 3 x , 4 y from dual">
<div>
<th:block th:each="item : ${list}">
<h3 th:text="${item.x} + ' - ' + ${item.y}">x - y</h3>
</th:block>
</div>
</dd:content>
</body>
</html>
(浏览器显示效果)
(swagger响应页面结果)
(swagger响应结果)
(1)引入<html xmlns:th="http://www.thymeleaf.org" xmlns:dd="http://www.w3.org/1999/xhtml" >空间,自定义标签的dd为标签的方言;
(2)<dd:format/>标签分别有th:type和th:value两个属性,均接收字符串类型参数值,type分别处理amount/datetime/ram/percentage/undefined几种类型的格式化类型,分别为格式化千分位金额/日期差/磁盘大小/百分比/未知类型等;
(3)raw-format为自定义属性,自定义属性有两种使用格式,分别是dd:raw-format='xxx'和data-dd-raw-format='yyy';
(4)<dd:content/>是一个用于测试将自定义标签与内置标签的结合使用,是个人比较喜欢的一种应用方式,比如上述示例中定义了sql属性和var属性,即将sql查询出来的结果集List赋值到list属性中,list属性保存在自定义标签dd:content的标签体范围内,再结合th:each进行循环输出最终得到上述的结果;
(5)其它API细节介绍:
//给标签增加自定义属性和属性值
structure.setAttribute("hello" , "world");
//将参数名和参数值保存在标签范围内中使用(未验证是在标签体范围内有效还是在整个页面范围有效)
structure.setLocalVariable("list" , list);
//获取属性名var的属性值
tag.getAttribute("var").getValue()
tag.getAttributeValue("value");
//删除原有标签
structure.removeTags();
//替换原有标签的内容体
structure.setBody(result , false);
//替换原有标签
structure.replaceWith(result , false);
源码工程下载:源码下载.zip;
点赞