Springboot2.x + thymeleaf自定义标签
版本
- springboot 2.x
- maven
- spring-boot-starter-thymeleaf
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
前端的标签
<smlai:select dicType="all" data-placeholder="选择类别" class="form-control chosen-select"
tabindex="2" style="width: 100%">
<option value="">选择类别</option>
</smlai:select>
自定义标签注入类
- IftgDialectEntrance
import org.springframework.stereotype.Component;
import org.thymeleaf.dialect.AbstractProcessorDialect;
import org.thymeleaf.dialect.IProcessorDialect;
import org.thymeleaf.processor.IProcessor;
import org.thymeleaf.standard.StandardDialect;
import java.util.HashSet;
import java.util.Set;
/**
* 自定注解处理入口
*/
@Component
public class IftgDialectEntrance extends AbstractProcessorDialect implements IProcessorDialect {
private static final String DIALECT_NAME = "samlai-dialect";
private static final String PREFIX = "smlai";
public IftgDialectEntrance() {
super(DIALECT_NAME, PREFIX, StandardDialect.PROCESSOR_PRECEDENCE);
}
@Override
public Set<IProcessor> getProcessors(String dialectPrefix) {
Set<IProcessor> processors = new HashSet<IProcessor>();
processors.add(new IftgSelectProcessor(PREFIX));
return processors;
}
}
自定义标签逻辑类
- IftgSelectProcessor
import java.util.List;
import com.sml.service.sys.DictService;
import com.sml.utils.IftgUtil;
import com.sml.vo.ValueVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.model.IModel;
import org.thymeleaf.model.IModelFactory;
import org.thymeleaf.model.IOpenElementTag;
import org.thymeleaf.model.IProcessableElementTag;
import org.thymeleaf.processor.element.AbstractElementTagProcessor;
import org.thymeleaf.processor.element.IElementTagStructureHandler;
import org.thymeleaf.spring5.context.SpringContextUtils;
import org.thymeleaf.templatemode.TemplateMode;
/**
* select 注解 用法 <smlai:select dicType = "dic_of_sex"></smlai:select> 属性
* dicType是必填项 --情况1:当dicType = 字典中的type 时select下拉数值渲染的value 为字典中的name字段,name
* 为字典中的name字段
*
*
* --情况2:当dicType = all时候表示select下拉数值渲染的value 为字典中的type字段,name
* 为字典中的description字段)
*
* 注: 控件的其他属性,用户可根据需求完全自定义,如需要加上name属性和Id属性则
* <smlai:select dicType = "dic_of_sex" name="mySelect" id=
* "selectId"></smlai:select>
*/
public class IftgSelectProcessor extends AbstractElementTagProcessor {
private DictService dictService;
private boolean firstLoad = true;
private static final String ATTR_NAME = "select";
private static final int PRECEDENCE = 120;
public IftgSelectProcessor(final String dialectPrefix) {
// // 此处理器将仅应用于HTML模式
// TemplateMode.HTML,
// // 要应用于名称的匹配前缀
// dialectPrefix,
// // 标签名称:匹配此名称的特定标签
// null,
// // 没有要应用于标签名称的前缀
// false,
// // 无属性名称:将通过标签名称匹配
// null,
// // 没有要应用于属性名称的前缀
// true,
// // 优先(内部方言自己的优先)
// PRECEDENCE
super(TemplateMode.HTML, dialectPrefix, ATTR_NAME, true, null, false, PRECEDENCE);
}
/**
* 核心处理
*
* @param context thymeleaf 上下文对象
* @param tag 当前节点对象
* @return
*/
@Override
protected void doProcess(ITemplateContext context, IProcessableElementTag tag,
IElementTagStructureHandler structureHandler) {
// 初始化
init(context);
// 获取值
String dicType = tag.getAttributeValue("dicType");// 字典类型
String defaultValue = tag.getAttributeValue("defaultValue");// 默认选中
String thValue = IftgUtil.getTargetAttributeValue(context, tag, "th:value");// 回显值
String defaultSelect = StringUtils.isNoneBlank(thValue) ? thValue : defaultValue;
List<ValueVO> valueVos = IftgUtil.getValues(dictService, dicType, new String[] { defaultSelect });
// 创建对象
createSelect(context, valueVos, structureHandler);
}
/**
* 初始化
*
* @param context
*/
private void init(ITemplateContext context) {
if (firstLoad) {
ApplicationContext appCtx = SpringContextUtils.getApplicationContext((ITemplateContext) context);
dictService = appCtx.getBean(DictService.class);
firstLoad = false;
}
}
/**
* 创建select对象
* @return
* 创建将替换自定义标签的DOM结构。 name将显示在“<span>”标签内, 因此必须首先创建, 然后必须向其中添加一个节点。
*
*/
private void createSelect(ITemplateContext context, List<ValueVO> options,
IElementTagStructureHandler structureHandler) {
final IModelFactory modelFactory = context.getModelFactory();
final IModel model = modelFactory.createModel();
//添加的element的dom对象并对其添加class的属性
model.add(modelFactory.createOpenElementTag("select", "class", "form-control chosen-select"));
model.add(modelFactory.createOpenElementTag("option"));
model.add(modelFactory.createText("选择类别"));
model.add(modelFactory.createCloseElementTag("option"));
// 创建option
for (ValueVO option : options) {
model.add(modelFactory.createOpenElementTag(String.format("option value='%s'", option.getVlaue())));
model.add(modelFactory.createText(option.getName()));
model.add(modelFactory.createCloseElementTag("option"));
IOpenElementTag el = modelFactory.createOpenElementTag("option");
}
model.add(modelFactory.createCloseElementTag("select"));
/*
* 指示引擎用指定的模型替换整个元素。
*/
structureHandler.replaceWith(model, false);
}
}
自定义标签的工具类
- IftgUtil
import com.google.common.collect.Lists;
import com.sml.dao.sys.Dict;
import com.sml.service.sys.DictService;
import com.sml.vo.ValueVO;
import org.apache.commons.lang3.StringUtils;
import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.model.IProcessableElementTag;
import org.thymeleaf.standard.expression.IStandardExpression;
import org.thymeleaf.standard.expression.IStandardExpressionParser;
import org.thymeleaf.standard.expression.StandardExpressions;
import org.thymeleaf.IEngineConfiguration;
import java.util.*;
/**
* IftgUtil 辅助工具类
*/
public class IftgUtil {
private static final String KEY_ALL = "all";
/**
* 获取数据
*
* @param dictService 字典service对象
* @param dicType 字典类型编码
* @return
*/
public static List<ValueVO> getValues(DictService dictService, String dicType) {
return getValues(dictService, dicType, null);
}
/**
* 获取数据
*
* @param dictService 字典service对象
* @param dicType 字典类型编码
* @param selectedValue 默认选中的值
* @return
*/
public static List<ValueVO> getValues(DictService dictService, String dicType, String[] selectedValue) {
if (StringUtils.isBlank(dicType)) {
return Lists.newArrayList();
}
if (KEY_ALL.contains(dicType)) {
return getListType(dictService, dicType, selectedValue);
}
Map<String, Object> map = new HashMap<>(16);
map.put("type", dicType);
List<Dict> dictDOS = dictService.list(dictService.getSimpleWrapper(map));
List<ValueVO> options = parseToValues(dictDOS, selectedValue);
return options;
}
public static List<ValueVO> getListType(DictService dictService, String dicType, String[] selectedValue) {
List<Dict> dictDOS = dictService.listType();
return parseListTypeToValues(dictDOS, selectedValue);
}
/**
* 获取标签对应值
* @param context thymeleaf 上下文对象
* @param element 当前节点对象
* @param attributeName 属性名
* @return 回显对象值
*/
public static List<String> getDataValues(ITemplateContext context, IProcessableElementTag element, String attributeName) {
String attributeValue = element.getAttributeValue(attributeName);
IEngineConfiguration configuration = context.getConfiguration();
IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(configuration);
IStandardExpression expression = null;
try {
expression = expressionParser.parseExpression( context, attributeValue);
} catch (Exception e) {
return null;
}
List<String> resp = new ArrayList<>();
Object result = expression.execute( context);
if (Objects.nonNull(result)
&& !(result instanceof String)) {
resp = (List<String>) (result);
return resp;
} else {
if(Objects.nonNull(result)){
resp.add(result.toString());
}
return resp;
}
}
/**
* 获取option 的值
* @param context thymeleaf 上下文对象
* @param element 当前节点对象
* @param attributeName 属性名
* @return 标签对象值
*/
public static String getTargetAttributeValue(ITemplateContext context, IProcessableElementTag element, String attributeName) {
String attributeValue = element.getAttributeValue(attributeName);
IEngineConfiguration configuration = context.getConfiguration();
IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(configuration);
IStandardExpression expression = null;
try {
expression = expressionParser.parseExpression(context, attributeValue);
} catch (Exception e) {
return null;
}
Object result = expression.execute(context);
return result == null ? "" : result.toString();
}
/**
* 转换格式
*
* @param dictDOS 待转换的字典数据
* @return 转换后的格式
*/
private static List<ValueVO> parseToValues(List<Dict> dictDOS, String[] selectedValue) {
List<ValueVO> valueVos = new ArrayList<>();
ValueVO valueVo = null;
List<String> selecteds = Objects.nonNull(selectedValue) ? Arrays.asList(selectedValue) : null;
for (Dict dictDO : dictDOS) {
valueVo = new ValueVO();
valueVo.setName(dictDO.getName());
valueVo.setVlaue(dictDO.getValue());
if (Objects.nonNull(selecteds) &&
selecteds.contains(dictDO.getValue())) {
valueVo.setSelected(true);
}
valueVos.add(valueVo);
}
return valueVos;
}
/**
* 转换格式(字典大类字典)
*
* @param dictDOS 待转换的字典数据
* @return 转换后的格式
*/
private static List<ValueVO> parseListTypeToValues(List<Dict> dictDOS, String[] selectedValue) {
List<ValueVO> valueVos = new ArrayList<>();
ValueVO valueVo = null;
List<String> selecteds = Objects.nonNull(selectedValue) ? Arrays.asList(selectedValue) : null;
for (Dict dictDO : dictDOS) {
valueVo = new ValueVO();
valueVo.setName(dictDO.getDescription());
valueVo.setVlaue(dictDO.getType());
if (Objects.nonNull(selecteds) &&
selecteds.contains(dictDO.getType())) {
valueVo.setSelected(true);
}
valueVos.add(valueVo);
}
return valueVos;
}
}
参考文章