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

Spring Boot MongoDB价格范围查询API问题排查求助

问题排查:Spring Boot MongoDB价格区间查询接口错误

问题描述

开发对接MongoDB Atlas集群的Spring Boot API,目标是实现根据动态传入的最小、最大价格值返回对应商品的接口。目前怀疑问题出在@Query和@PathVariable的使用上,考虑改用@RequestParam传递参数,但不确定Repository中@Query该如何调整,请求排查错误。

现有代码

Repository代码

package com.webshoppingbackend.springboot.repository;

import java.util.List;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;

import com.webshoppingbackend.springboot.model.WebShoppingItem;

public interface WebShoppingRepository extends MongoRepository<WebShoppingItem, String> {

    @Query("{category:?0}")
    List<WebShoppingItem> getItemsByCategory(String category);

    @Query("{brand:?0}")
    List<WebShoppingItem> getItemsByBrand(String brand);

    @Query("{price:{$lt:?0,$gt:?1}}")
    List<WebShoppingItem> getItemsBasedOnPrice(long higherPrice, long lowerPrice);

}

Controller代码

package com.webshoppingbackend.springboot.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.webshoppingbackend.springboot.model.WebShoppingItem;
import com.webshoppingbackend.springboot.services.WebShoppingService;

@RestController
@RequestMapping("/webshopping")
public class WebShoppingController {
    @Autowired
    private WebShoppingService service;

    @GetMapping
    public List<WebShoppingItem> getAllItems() {
        return service.getWebShoppingItems();
    }

    @GetMapping("/{itemId}")
    public WebShoppingItem getItem(@PathVariable String itemId) {
        return service.getItemById(itemId);
    }

    @GetMapping("/category/{category}")
    public List<WebShoppingItem> getItemsByCategory(@PathVariable String category) {
        return service.getItemsByCategory(category);
    }

    @GetMapping("/brand/{brand}")
    public List<WebShoppingItem> getItemsByBrand(@PathVariable String brand) {
        return service.getItemsByBrand(brand);
    }

    @GetMapping("/{price}")
    public List<WebShoppingItem> getItemsBasedOnPriceRange(@PathVariable long higherPrice,
            @PathVariable long lowerPrice) {
        return service.getItemsBasedOnPriceRange(higherPrice, lowerPrice);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public WebShoppingItem addItem(@RequestBody WebShoppingItem webShoppingItem) {
        return service.addToWebShoppingItems(webShoppingItem);
    }

    @PutMapping
    public WebShoppingItem modifyItem(@RequestBody WebShoppingItem webShoppingItem) {
        return service.updateWebShoppingItem(webShoppingItem);
    }

    @DeleteMapping("/{itemId}")
    public String deleteItem(@PathVariable String itemId) {
        return service.deleteWebShoppingItem(itemId);
    }
}

Service代码

package com.webshoppingbackend.springboot.services;

import java.util.List;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.webshoppingbackend.springboot.model.WebShoppingItem;
import com.webshoppingbackend.springboot.repository.WebShoppingRepository;

@Service
public class WebShoppingService {
    @Autowired
    private WebShoppingRepository repository;

    // CRUD

    public WebShoppingItem addToWebShoppingItems(WebShoppingItem webShoppingItem) {
        webShoppingItem.setItemId(UUID.randomUUID().toString().split("-")[0]);
        return repository.save(webShoppingItem);
    }

    public List<WebShoppingItem> getWebShoppingItems() {
        return repository.findAll();
    }

    public WebShoppingItem getItemById(String itemId) {
        return repository.findById(itemId).get();
    }

    public List<WebShoppingItem> getItemsByCategory(String category) {
        return repository.getItemsByCategory(category);
    }

    public List<WebShoppingItem> getItemsByBrand(String brand) {
        return repository.getItemsByBrand(brand);
    }

    public List<WebShoppingItem> getItemsBasedOnPriceRange(long higherPrice, long lowerPrice) {
        return repository.getItemsBasedOnPrice(higherPrice, lowerPrice);
    }

    public WebShoppingItem updateWebShoppingItem(WebShoppingItem webShoppingItem) {
        WebShoppingItem itemToBeUpdated = repository.findById(webShoppingItem.getItemId()).get();
        itemToBeUpdated.setCategory(webShoppingItem.getCategory());
        itemToBeUpdated.setProductName(webShoppingItem.getProductName());
        itemToBeUpdated.setImageSource(webShoppingItem.getImageSource());
        itemToBeUpdated.setBrand(webShoppingItem.getBrand());
        itemToBeUpdated.setPrice(webShoppingItem.getPrice());
        itemToBeUpdated.setRating(webShoppingItem.getRating());
        itemToBeUpdated.setShippingCharges(webShoppingItem.getShippingCharges());
        itemToBeUpdated.setProductDetails(webShoppingItem.getProductDetails());
        return repository.save(itemToBeUpdated);
    }

    public String deleteWebShoppingItem(String itemId) {
        repository.deleteById(itemId);
        return "Deleted Web Shopping Item";
    }
}

请求情况

使用Talend API Tester发送请求,路径为/webshopping/100/50,尝试传入最高价格100、最低价格50,但接口无法正确返回结果。

问题分析与修正方案

1. Controller路径与参数绑定错误

原Controller中@GetMapping("/{price}")仅定义了一个路径变量,但方法声明了两个@PathVariable,Spring无法正确解析参数,直接导致路径匹配失败。且价格区间属于查询过滤参数,不符合REST路径变量的使用场景,应改用@RequestParam传递。

修改Controller中的价格区间接口:

@GetMapping("/price-range")
public List<WebShoppingItem> getItemsBasedOnPriceRange(
        @RequestParam("minPrice") long minPrice,
        @RequestParam("maxPrice") long maxPrice) {
    return service.getItemsBasedOnPriceRange(maxPrice, minPrice);
}

2. Repository中@Query的参数逻辑确认

原@Query("{price:{$lt:?0,$gt:?1}}")逻辑为price < 第一个参数(higherPrice)且price > 第二个参数(lowerPrice),逻辑本身正确,但参数顺序容易混淆。可以改用命名参数提升可读性:

修改Repository方法:

import org.springframework.data.repository.query.Param;

// ...

@Query("{price: {$gt: :#{#minPrice}, $lt: :#{#maxPrice}}}")
List<WebShoppingItem> getItemsBasedOnPrice(@Param("minPrice") long minPrice, @Param("maxPrice") long maxPrice);

对应的Service方法同步调整参数顺序:

public List<WebShoppingItem> getItemsBasedOnPriceRange(long minPrice, long maxPrice) {
    return repository.getItemsBasedOnPrice(minPrice, maxPrice);
}

3. 请求方式调整

修改后,请求URL格式应为/webshopping/price-range?minPrice=50&maxPrice=100,通过查询参数清晰传递最小和最大价格。

总结

  • @PathVariable适合标识资源唯一ID,查询过滤类参数(如价格区间)应使用@RequestParam;
  • 确保Repository中@Query的参数顺序或命名与方法参数一致,避免逻辑错误;
  • 调整Controller接口的参数绑定方式后,使用正确的查询参数格式发送请求即可解决问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 11:33:46