簡體   English   中英

如何為有和無請求參數的請求定義不同的Spring MVC請求處理程序?

[英]How to define different Spring MVC request handlers for requsest with and without request parameters?

Spring MVC是否可以為沒有請求參數的請求和具有請求參數的請求定義不同的處理程序?

有一個簡單的控制器:

@RestController
@RequestMapping("/strategies")
public class StrategyController {
    ...

    @GetMapping
    public List<Strategy> getAll() {
        return service.getBeans().stream()
            .map(mapper::toDto)
            .collect(toList());
    }

    @GetMapping
    public List<Strategy> search(StrategyFilter filter) {
        return service.search(new StrategySearchSpecification(
                filter.getCode(),
                filter.getName(),
                filter.getType()
            )).stream()
            .map(mapper::toDto)
            .collect(toList());
    }
}

我想要getAll()方法來處理沒有請求參數的請求: /strategies

我想使用search(StrategyFilter filter)方法來處理帶有請求參數的請求: /strategies?name=SomeName&type=SomeType

似乎不可能通過@GetMapping params屬性來區分這種情況,因為StrategyFilter任何屬性都可以省略。

在這種配置下,我得到一個明顯的錯誤:

Caused by: java.lang.IllegalStateException: Ambiguous mapping. 
Cannot map 'strategyController' method 
public List<Strategy> StrategyController.getAll() to {[/strategies],methods=[GET]}: 

There is already 'strategyController' bean method public List<Strategy> StrategyController.search(StrategyFilter) mapped.

當然,可以這樣寫:

@GetMapping
public List<Strategy> get(StrategyFilter filter) {
    return noFilterProvided(filter) ? getAll() : search(filter);
}

但是,每當過濾器的屬性數量發生變化時,都必須更改“ noFilterProvided(StrategyFilter filter)”。

Spring框架使用基於點的匹配。 它從可用的匹配項中選擇最高匹配項。 合格標准越多,得分越高。 如果您在一個匹配項中定義了所請求的查詢參數,則該參數存在時將被接受。 其他情況另類。

要定義請求的參數,請將它們作為直接屬性而不是StrategyFilter屬性傳遞。 在缺少參數的情況下,也可以像這樣成功初始化實例(這些attrs不會被初始化,它們保持默認狀態:“” / 0 / false)。 因此出現了模糊的匹配錯誤。

最后:使用直接屬性代替StrategyFilter。

設計的另一個問題是直接的StrategySearchSpecification實例化。 不能以這種方式進行單元測試。 將其定義為Spring Component。

@Component
@Getter // Lombok annotation to generate getter methods
@Setter // Lombok annotation to generate setter methods
public class StrategySearchSpecification
{
  private CODE_TYPE code;
  private String name;
  private TYPE_TYPE type;
}

並將其作為參數注入(正確的實現/模擬)並使用其setter方法。

@RestController
@RequestMapping("/strategies")
public class StrategyController {
    ...

    @GetMapping
    public List<Strategy> getAll() {
        return service.getBeans().stream()
            .map(mapper::toDto)
            .collect(toList());
    }

    @GetMapping
    public List<Strategy> search(@RequestParam CODE_TYPE code, @RequestParam String name, @RequestParam TYPE_TYPE type, StrategySearchSpecification specification ) {
        specification.setCode( code );
        specification.setName( name );
        specification.setType( type );
        return service.search( specification
            )).stream()
            .map(mapper::toDto)
            .collect(toList());
    }
}

如果StrategyFilter具有nametype的屬性,則應該可以使用:

@RestController
@RequestMapping("/strategies")
public class StrategyController {
    ...

    @GetMapping
    public List<Strategy> getAll() {
        return service.getBeans().stream()
            .map(mapper::toDto)
            .collect(toList());
    }

    @GetMapping("{name}/{type}")
    public List<Strategy> search(StrategyFilter filter) {
        return service.search(new StrategySearchSpecification(
                filter.getCode(),
                filter.getName(),
                filter.getType()
            )).stream()
            .map(mapper::toDto)
            .collect(toList());
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM