下面给出一个“最小可运行”的完整 Demo,复制即可启动。
 项目:SpringBoot 2.7 + Thymeleaf + layui-mini(单页 tab 版)。
 功能:左侧菜单由后端动态渲染,点击菜单只在右侧新增 tab,不整页刷新。
-  
目录结构
 
复制
src
└─ main
   ├─ java
   │  └─ com.example.demo
   │     ├─ DemoApplication.java
   │     └─ MenuController.java
   ├─ resources
   │  ├─ application.yml
   │  └─ templates
   │     ├─ index.html
   │     └─ pages
   │        ├─ welcome.html
   │        └─ user
   │           └─ list.html
   └─ webapp
      └─ layui      ← 官网下载后整个文件夹放这里 
-  
依赖(pom.xml 片段)
 
xml
复制
<dependencies>
    <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>
</dependencies> 
-  
配置(application.yml)
 
yaml
复制
spring:
  thymeleaf:
    cache: false
server:
  port: 8080 
-  
启动类
 
java
复制
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
} 
-  
控制器(MenuController.java)
 
java
复制
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.*;
@Controller
public class MenuController {
    /* 首页:返回主框架 + 菜单数据 */
    @GetMapping("/")
    public String index(Model model) {
        model.addAttribute("menus", buildMenu());
        model.addAttribute("nick", "管理员");
        return "index";
    }
    /* 以下三个接口只返回片段(Thymeleaf fragment),供 tab 动态加载 */
    @GetMapping("/welcome")
    public String welcome() {
        return "pages/welcome :: content";
    }
    @GetMapping("/user/list")
    public String userList() {
        return "pages/user/list :: content";
    }
    @GetMapping("/order/list")
    public String orderList() {
        return "pages/order/list :: content";
    }
    /* 模拟两级菜单数据 */
    private List<MenuVo> buildMenu() {
        List<MenuVo> list = new ArrayList<>();
        MenuVo sys = new MenuVo("100", "系统管理", "layui-icon-set", null);
        sys.setChildren(Arrays.asList(
                new MenuVo("1001", "用户管理", null, "/user/list"),
                new MenuVo("1002", "角色管理", null, "/role/list")
        ));
        list.add(sys);
        MenuVo order = new MenuVo("200", "订单中心", "layui-icon-template", null);
        order.setChildren(Arrays.asList(
                new MenuVo("2001", "订单列表", null, "/order/list")
        ));
        list.add(order);
        return list;
    }
    /* ===== 内部 VO ===== */
    public static class MenuVo {
        private String id;
        private String title;
        private String icon;
        private String href;
        private List<MenuVo> children;
        public MenuVo(String id, String title, String icon, String href) {
            this.id = id;
            this.title = title;
            this.icon = icon;
            this.href = href;
        }
        /* getter / setter 省略,用 Lombok 亦可 */
        public String getId() { return id; }
        public String getTitle() { return title; }
        public String getIcon() { return icon; }
        public String getHref() { return href; }
        public List<MenuVo> getChildren() { return children; }
        public void setChildren(List<MenuVo> children) { this.children = children; }
    }
} 
-  
主框架模板(templates/index.html)
 
HTML
预览
复制
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <title>layui-mini 演示</title>
    <link rel="stylesheet" th:href="@{/layui/css/layui.css}">
    <style>
        .layui-tab{ position:absolute; left:200px; top:0; right:0; bottom:0;}
        .layui-tab-content{ position:absolute; top:40px; left:0; right:0; bottom:0;}
        .layui-tab-item{ height:100%;}
        iframe{width:100%;height:100%;border:0}
    </style>
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
    <!-- 左侧 -->
    <div class="layui-side layui-bg-black">
        <div class="layui-side-scroll">
            <ul class="layui-nav layui-nav-tree" lay-filter="side">
                <li th:each="m:${menus}" class="layui-nav-item">
                    <a th:if="${m.children==null}" href="javascript:;"
                       th:lay-href="@{${m.href}}" th:text="${m.title}">菜单</a>
                    <a th:if="${m.children!=null}" href="javascript:;">
                        <i th:if="${m.icon}" th:class="${m.icon}"></i>
                        <span th:text="${m.title}">父菜单</span>
                    </a>
                    <dl th:if="${m.children!=null}" class="layui-nav-child">
                        <dd th:each="c:${m.children}">
                            <a href="javascript:;" th:lay-href="@{${c.href}}" th:text="${c.title}">子菜单</a>
                        </dd>
                    </dl>
                </li>
            </ul>
        </div>
    </div>
    <!-- 右侧主体 -->
    <div class="layui-body">
        <div class="layui-tab layui-tab-brief" lay-filter="tab" lay-allowclose="true">
            <ul class="layui-tab-title">
                <li class="layui-this">首页</li>
            </ul>
            <div class="layui-tab-content">
                <div class="layui-tab-item layui-show">
                    <iframe th:src="@{/welcome}"></iframe>
                </div>
            </div>
        </div>
    </div>
</div>
<script th:src="@{/layui/layui.js}"></script>
<script>
    layui.use(['element','jquery'], function(){
        var element = layui.element,
            $ = layui.jquery;
        /* 点击左侧菜单 → 新增 tab */
        $(document).on('click','a[lay-href]',function(){
            var url = $(this).attr('lay-href');
            var title = $(this).text();
            var id = 'tab-' + url.replace(/\//g,'-');
            if($('.layui-tab-title li[lay-id="'+id+'"]').length>0){
                element.tabChange('tab', id);
            }else{
                element.tabAdd('tab',{
                    title:title,
                    content:'<iframe src="'+ url +'"></iframe>',
                    id:id
                });
                element.tabChange('tab', id);
            }
        });
    });
</script>
</body>
</html> 
-  
片段页面(仅返回 tab 里的内容)
 
templates/pages/welcome.html
HTML
预览
复制
<div xmlns:th="http://www.thymeleaf.org" th:fragment="content">
  <div style="padding:20px;">
      <h2>欢迎使用 layui-mini + Thymeleaf</h2>
      <p>当前用户:[[${nick}]]</p>
  </div>
</div> 
templates/pages/user/list.html
HTML
预览
复制
<div xmlns:th="http://www.thymeleaf.org" th:fragment="content">
  <div style="padding:20px;">
      <button class="layui-btn layui-btn-sm">新增用户</button>
      <table class="layui-table">
          <thead><tr><th>ID</th><th>姓名</th></tr></thead>
          <tbody><tr><td>1</td><td>张三</td></tr></tbody>
      </table>
  </div>
</div> 
-  
运行
 
mvn spring-boot:run
浏览器打开 http://localhost:8080/
-  
左侧“系统管理 → 用户管理”点击后,右侧动态出现“用户列表” tab
 -  
全程只刷新 iframe,不会整页跳转,已达到 layui-mini 单页效果
 
这就是一个完整可跑的“Thymeleaf + layui-mini”菜单与控制器关联的 最小真实例子。
                  
                  
                  
                  
      
          
                
                
                
                
              
                
                
                
                
                
              
                
                
              
            
                  
被折叠的  条评论
		 为什么被折叠?
		 
		 
		
    
  
    
  
            


            