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

Spring Boot从MySQL单表实现动态下拉框并对接React REST API

完全可以用单个实体/表实现,不需要多表关联。下面分后端(Spring Boot)和前端(React)两部分给你具体实现步骤:

后端实现(Spring Boot)

1. 定义实体类(对应单表)

假设你的MySQL表叫products,结构如下:

CREATE TABLE products (
    id INT PRIMARY KEY AUTO_INCREMENT,
    category VARCHAR(50) NOT NULL,
    brand VARCHAR(50) NOT NULL,
    product_name VARCHAR(100) NOT NULL
);

对应的实体类:

import jakarta.persistence.*;
import lombok.Data;

@Entity
@Table(name = "products")
@Data // 用lombok简化getter/setter,也可以手动写
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    private String category;
    private String brand;
    
    @Column(name = "product_name")
    private String productName;
}

2. 编写Repository层

基于JPA实现单表的过滤查询,这里提供两种方式:固定参数方法和灵活的动态查询(适合初学者先从固定方法入手):

import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface ProductRepository extends JpaRepository<Product, Integer> {
    // 按分类过滤
    List<Product> findByCategory(String category);
    // 按品牌过滤
    List<Product> findByBrand(String brand);
    // 同时按分类+品牌过滤
    List<Product> findByCategoryAndBrand(String category, String brand);
}

如果需要支持任意列的动态过滤,后续可以改用JpaSpecificationExecutor扩展,但上面的方法足够覆盖基础需求。

3. 编写REST Controller

提供接口接收前端的过滤参数,返回对应数据:

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
@RequestMapping("/api/products")
@CrossOrigin(origins = "http://localhost:3000") // 解决跨域,对应React端口
public class ProductController {
    private final ProductRepository productRepository;

    // 构造注入
    public ProductController(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    // 动态过滤接口,参数可选
    @GetMapping("/filter")
    public List<Product> getFilteredProducts(
            @RequestParam(required = false) String category,
            @RequestParam(required = false) String brand
    ) {
        if (category != null && brand != null) {
            return productRepository.findByCategoryAndBrand(category, brand);
        } else if (category != null) {
            return productRepository.findByCategory(category);
        } else if (brand != null) {
            return productRepository.findByBrand(brand);
        } else {
            // 无过滤条件时返回全量数据
            return productRepository.findAll();
        }
    }
}

4. 数据库配置

在application.properties中配置MySQL连接:

spring.datasource.url=jdbc:mysql://localhost:3306/your_db_name?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=your_db_password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

前端实现(React)

基础React组件

用useState管理过滤条件、下拉选项和选中值,useEffect监听条件变化自动请求数据:

import { useState, useEffect } from 'react';

function ProductDropdown() {
    // 状态管理
    const [products, setProducts] = useState([]);
    const [selectedProduct, setSelectedProduct] = useState('');
    const [filterCategory, setFilterCategory] = useState('');
    const [filterBrand, setFilterBrand] = useState('');

    // 发起API请求的函数
    const fetchProducts = async () => {
        const params = new URLSearchParams();
        if (filterCategory) params.append('category', filterCategory);
        if (filterBrand) params.append('brand', filterBrand);

        try {
            const response = await fetch(`http://localhost:8080/api/products/filter?${params}`);
            const data = await response.json();
            setProducts(data);
        } catch (error) {
            console.error('获取数据失败:', error);
        }
    };

    // 初始加载+过滤条件变化时重新请求
    useEffect(() => {
        fetchProducts();
    }, [filterCategory, filterBrand]);

    return (
        <div style={{ padding: '20px' }}>
            {/* 过滤输入区 */}
            <div>
                <label>按分类过滤:</label>
                <input
                    type="text"
                    value={filterCategory}
                    onChange={(e) => setFilterCategory(e.target.value)}
                    placeholder="输入分类"
                    style={{ margin: '0 10px' }}
                />
                <label>按品牌过滤:</label>
                <input
                    type="text"
                    value={filterBrand}
                    onChange={(e) => setFilterBrand(e.target.value)}
                    placeholder="输入品牌"
                />
            </div>

            {/* 动态下拉框 */}
            <div style={{ marginTop: '20px' }}>
                <label>选择产品:</label>
                <select
                    value={selectedProduct}
                    onChange={(e) => setSelectedProduct(e.target.value)}
                >
                    <option value="">请选择</option>
                    {products.map(product => (
                        <option key={product.id} value={product.id}>
                            {product.productName} ({product.brand} - {product.category})
                        </option>
                    ))}
                </select>
            </div>
        </div>
    );
}

export default ProductDropdown;

关键说明
  1. 单表实现核心:所有过滤逻辑都基于单表的字段,通过Repository的查询方法直接操作单表,不需要关联任何其他实体或表。
  2. 扩展灵活性:如果后续需要支持更多列的过滤,只需要在Repository中新增对应的查询方法,或者改用Specification实现更灵活的动态查询,无需新增表结构。
  3. 跨域处理:后端的@CrossOrigin注解是为了解决React和Spring Boot端口不同导致的跨域问题,实际部署时可以通过Nginx反向代理替代。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 10:31:31