springboot 学习 —— springboot 2.x ,thymeleaf 自定义 select 标签

1、添加依赖

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

2、注册自定义标签

import java.util.HashSet;
import java.util.Set;
 
import org.springframework.stereotype.Component;
import org.thymeleaf.dialect.AbstractProcessorDialect;
import org.thymeleaf.processor.IProcessor;
import org.thymeleaf.standard.StandardDialect;
 
/**
 * 类说明:自定标签注册类
 */
@Component
public class CustomLabel extends AbstractProcessorDialect{
 
	/**
	 * 定义方言名称
	 */
	private static final String NAME="系统自定义标签";
	
	/**
	 * 定义方言属性
	 */
	private static final String PREFIX="bm";

	protected CustomLabel() {
		super(NAME, PREFIX, StandardDialect.PROCESSOR_PRECEDENCE);
	}
 
	@Override
	public Set<IProcessor> getProcessors(final String dialectPrefix) {
		final Set<IProcessor> processor=new HashSet<>();
		processor.add(new CustomLabelSelect(PREFIX));  // <bm:select>标签
		// 如果有多个标签时,在下面添加
		//processor.add(new CustomLabelSelect(PREFIX));   
		return processor;
	} 
}

3、自定义标签实现类

import java.util.ArrayList;
import java.util.List;

import cn.hutool.core.util.StrUtil;
import com.xxx.app.common.utils.SpringContextHolder;
import com.xxx.app.modules.service.SysDictService;
import com.xxx.app.modules.service.impl.SysDictServiceImpl;
import com.xxx.app.modules.vo.SysDictShowVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
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.standard.expression.Expression;
import org.thymeleaf.standard.expression.StandardExpressionParser;
import org.thymeleaf.templatemode.TemplateMode;
import org.unbescape.html.HtmlEscape;


/**
 * 类说明:自定义select标签,使用方法:
 * <pre>
 * <bm:select class="" id="testSelect" name="testSelect" dictType="字典类型" headerLabel="请选择" headerValue="" th:value="${xxx.xxx}"></bm:select>
 * </pre>
 */
public class CustomLabelSelect extends AbstractElementTagProcessor {

    private static final String TAG_NAME  = "select";//标签名 select 这个玩意就是 自定义标签的 : select, 应该是可以定义多个标签
    private static final int PRECEDENCE = 1000;//优先级


    public CustomLabelSelect(String dialectPrefix) {
        super(TemplateMode.HTML, // 此处理器将仅应用于HTML模式
                dialectPrefix, // 要应用于名称的匹配前缀
                TAG_NAME, // 标签名称:匹配此名称的特定标签
                true, // 没有应用于标签名的前缀
                null, // 无属性名称:将通过标签名称匹配
                false, // 没有要应用于属性名称的前缀
                PRECEDENCE// 优先(内部方言自己的优先
        );
    }

    @Override
    protected void doProcess(ITemplateContext context, IProcessableElementTag tag,
                             IElementTagStructureHandler structureHandler) {

        //1、创建模型
        IModelFactory modelFactory = context.getModelFactory();
        IModel model = modelFactory.createModel();

        //2、创建模型元素 <select>
        IOpenElementTag openElementTag = createModelElement(tag,modelFactory);
        model.add(openElementTag);//<select>

        // 3、组装 options
        List<String> options=createOptions(context,tag);
        model.add(modelFactory.createText(HtmlEscape.unescapeHtml(String.join("\n", options))));

        //4、关闭</select>
        model.add(modelFactory.createCloseElementTag("select"));

        //5、替换前面的标签
        structureHandler.replaceWith(model, false);
    }


    /**
     * 添加模型元素
     * @param tag
     * @param modelFactory
     * @return
     */
    private IOpenElementTag createModelElement(IProcessableElementTag tag, IModelFactory modelFactory) {
        String classValue = tag.getAttributeValue("class");
        String id = tag.getAttributeValue("id");
        String name = tag.getAttributeValue("name");
        String style = tag.getAttributeValue("style");
        String disabled = tag.getAttributeValue("disabled");
        IOpenElementTag openElementTag = modelFactory.createOpenElementTag("select", "class", classValue);
        if (!StringUtils.isEmpty(id)) {
            openElementTag=modelFactory.setAttribute(openElementTag, "id", id);
        }
        if (!StringUtils.isEmpty(name)) {
            openElementTag=modelFactory.setAttribute(openElementTag, "name", name);
        }
        if (!StringUtils.isEmpty(style)) {
            openElementTag=modelFactory.setAttribute(openElementTag, "style", style);
        }
        if (!StringUtils.isEmpty(disabled)) {
            openElementTag=modelFactory.setAttribute(openElementTag, "disabled", disabled);
        }
        return openElementTag;
    }


    /**
     * 组装 options
     * @param context
     * @param tag
     * @return
     */
    private List<String> createOptions(ITemplateContext context,IProcessableElementTag tag){
        //1、select的option
        List<String> options=new ArrayList<>();
        
        //2、设置认值
        String defaultHtml = addDefault(tag);
        if (StringUtils.isNotBlank(defaultHtml)){
            options.add(0,defaultHtml);
        }

        //3、根据字典类型获取数据,如果有value值,则认选中
        String ptionHtml = getDictDateByType(tag,context);
        options.add(ptionHtml);
        return options;
    }

    /**
     * 添加认值
     * @param tag
     * @return
     */
    private String addDefault(IProcessableElementTag tag) {
        String headerLabel = tag.getAttributeValue("headerLabel");
        String headerValue = tag.getAttributeValue("headerValue");
        StringBuilder sb = new StringBuilder("");
        if (!StringUtils.isEmpty(headerLabel)) {
            sb.append("\n<option value='" + headerValue + "' >");
            sb.append(headerLabel + "</option>");
        }
        return sb.toString();
    }

    /**
     * 根据字典类型获取数据
     * @param tag
     * @param context
     * @return
     */
    private String getDictDateByType(IProcessableElementTag tag, ITemplateContext context) {
    
    	// select 中增加了 dictType 属性,用其值 从缓存、、配置、或数据库获取数据。
        String dictType = tag.getAttributeValue("dictType");
        if (StringUtils.isEmpty(dictType)) {
            return "";
        }
        String value = tag.getAttributeValue("th:value");
        Object executeExpression = null;
        if (!StringUtils.isEmpty(value)) {
            // 执行 th:value ,得到其值
            executeExpression = executeExpression(value, context);
        }
        
        // 重点说明:
        // 这块是从缓存、配置文件 或者 数据库 等中,查询得到数据,用来组装 option 标签
        SysDictService sysDictService=SpringContextHolder.getBean(SysDictServiceImpl.class);
        List<SysDictShowVO> dicts =  sysDictService.getListByKey(StrUtil.trim(dictType));
        if (CollectionUtils.isEmpty(dicts)) {
            return "";
        }

		// option 标签组装
        StringBuilder sb = new StringBuilder();
        for (int i = 0, len = dicts.size(); i < len; i++) {
            SysDictShowVO   sysDictShowVO = dicts.get(i);
            if (executeExpression != null && executeExpression.toString().equals(sysDictShowVO.getDictValue())) {
                sb.append("<option value='" +sysDictShowVO.getDictValue() + "' selected=\"selected\">");
            } else {
                sb.append("<option value='" +sysDictShowVO.getDictValue() + "' >");
            }
            sb.append(sysDictShowVO.getDictName() + "</option>\n");
        }
        return sb.toString();
    }

    /**
     * 执行自定义标签中的表达式
     * @param value
     * @param context
     * @return
     */
    private Object executeExpression(String value, ITemplateContext context) {
        StandardExpressionParser parser = new StandardExpressionParser();
        Expression parseExpression = parser.parseExpression(context, value);
        Object execute = parseExpression.execute(context);
        return execute;
    }
}

4、使用

<!--  没有 th:value ,与普通的select基本一样  -->
<bm:select   id="status" name="status" dictType="status_type" 
		 headerLabel="请选择" headerValue=""  class="form-control" ></bm:select>

<!--  如有 th:value 时,则可以选中option中与之匹配的值  -->
<bm:select   id="status" name="status" dictType="status_type" th:value="${ companys['status'] }" 
		 headerLabel="请选择" headerValue=""  class="form-control" ></bm:select>

解析后的源代码

在这里插入图片描述

5、转载

thymeleaf 自定义标签,解析表达式:https://blog.csdn.net/z793397795/article/details/97389063

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...