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

