You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+Thymeleaf实现二级联动下拉列表技术咨询

Spring Boot + Thymeleaf 实现二级联动下拉列表

嘿,这个二级联动的需求在Spring Boot+Thymeleaf项目里太常见啦!我来给你两种靠谱的实现方案,你可以根据自己的场景选:

方案一:前端预加载所有关联数据(适合数据量不大的场景)

这种方案完全匹配你的情况——既然你已经在后端准备好所有关联数据了,直接把数据传到前端,用JavaScript监听下拉变化就能动态更新第二个列表。

1. 后端控制器传递数据

假设第一个下拉是「分类」,第二个是「分类下的产品」,你需要把分类列表和「分类ID-产品列表」的映射关系传到模板:

@Controller
public class CategoryController {

    @Autowired
    private CategoryService categoryService;
    @Autowired
    private ProductService productService;

    @GetMapping("/form")
    public String showForm(Model model) {
        // 第一个下拉的分类数据
        List<Category> categories = categoryService.getAllCategories();
        // 分类ID对应的产品列表映射
        Map<Long, List<Product>> categoryProductMap = productService.getProductsGroupedByCategory();
        
        model.addAttribute("categories", categories);
        // 把Map转成JSON字符串,方便前端JS解析
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String categoryProductJson = objectMapper.writeValueAsString(categoryProductMap);
            model.addAttribute("categoryProductJson", categoryProductJson);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        
        return "form";
    }
}

2. Thymeleaf模板渲染第一个下拉并预存数据

在Thymeleaf页面里,先渲染第一个下拉列表,同时把关联数据存到JavaScript对象中:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>二级联动示例</title>
</head>
<body>
    <!-- 第一个下拉列表 -->
    <select id="categorySelect">
        <option value="">请选择分类</option>
        <option th:each="category : ${categories}" 
                th:value="${category.id}" 
                th:text="${category.name}">
        </option>
    </select>

    <!-- 第二个下拉列表,初始为空 -->
    <select id="productSelect">
        <option value="">请先选择分类</option>
    </select>

    <script>
        // 把后端传递的JSON字符串转成JS对象
        const categoryProductMap = JSON.parse('[[${categoryProductJson}]]');
        
        // 监听第一个下拉的变化事件
        document.getElementById('categorySelect').addEventListener('change', function() {
            const selectedCategoryId = this.value;
            const productSelect = document.getElementById('productSelect');
            
            // 清空第二个下拉的现有选项
            productSelect.innerHTML = '<option value="">请选择产品</option>';
            
            // 如果选中了有效分类,添加对应的产品选项
            if (selectedCategoryId) {
                const products = categoryProductMap[selectedCategoryId];
                products.forEach(product => {
                    const option = document.createElement('option');
                    option.value = product.id;
                    option.textContent = product.name;
                    productSelect.appendChild(option);
                });
            }
        });
    </script>
</body>
</html>

方案二:异步AJAX请求(适合数据量大的场景)

如果关联数据量很大,预加载会导致页面加载慢,那就用异步请求的方式:当选中第一个下拉的选项时,前端向后端发请求获取对应的第二个列表数据。

1. 后端新增接口返回关联数据

@RestController
@RequestMapping("/api")
public class ProductApiController {

    @Autowired
    private ProductService productService;

    @GetMapping("/products")
    public List<Product> getProductsByCategoryId(@RequestParam Long categoryId) {
        return productService.getProductsByCategoryId(categoryId);
    }
}

2. Thymeleaf模板+AJAX实现联动

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>二级联动示例</title>
</head>
<body>
    <select id="categorySelect">
        <option value="">请选择分类</option>
        <option th:each="category : ${categories}" 
                th:value="${category.id}" 
                th:text="${category.name}">
        </option>
    </select>

    <select id="productSelect">
        <option value="">请先选择分类</option>
    </select>

    <script>
        document.getElementById('categorySelect').addEventListener('change', async function() {
            const selectedCategoryId = this.value;
            const productSelect = document.getElementById('productSelect');
            
            productSelect.innerHTML = '<option value="">加载中...</option>';
            
            if (!selectedCategoryId) {
                productSelect.innerHTML = '<option value="">请选择分类</option>';
                return;
            }
            
            // 发送AJAX请求获取产品数据
            try {
                const response = await fetch(`/api/products?categoryId=${selectedCategoryId}`);
                const products = await response.json();
                
                // 渲染第二个下拉
                productSelect.innerHTML = '<option value="">请选择产品</option>';
                products.forEach(product => {
                    const option = document.createElement('option');
                    option.value = product.id;
                    option.textContent = product.name;
                    productSelect.appendChild(option);
                });
            } catch (error) {
                productSelect.innerHTML = '<option value="">加载失败,请重试</option>';
                console.error('加载产品数据失败:', error);
            }
        });
    </script>
</body>
</html>

小提示

  • 确保实体类(比如Category、Product)有正确的id和name字段,序列化JSON时能正常输出这些字段。
  • 方案一中,Thymeleaf的[[${}]]会自动处理HTML转义,不用担心XSS问题。
  • 可以根据需求给第二个下拉添加默认选中项,或者在页面加载完成时自动触发第一个下拉的change事件,加载默认分类的产品。

内容的提问来源于stack exchange,提问作者Emmerson Deneir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:12:01