首页 > 解决方案 > 在遵循 RESTful API 标准的同时,在同一控制器中拥有 getAll、getById 和 getByEmail 的控制器方法

问题描述

我有一个实体Users,其中包含idand emailAddress。我想编写一个同时具有 3 个 get 方法的控制器:

注意:两段代码的区别在于两者中最后一个函数的参数(第一个是@PathVariable,第二个是@RequestParam.

我尝试了两种方法来实现这一点(都遇到了一个单独的问题),第一种是:

@GetMapping
  @ApiOperation(value = "List all Users")
  @ApiResponses({
    @ApiResponse(code = 200, message = "OK", response = User.class, responseContainer = "List"),
    @ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
    @ApiResponse(code = 404, message = "Not Found", response = Error.class),
    @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
  })
  @Transactional(readOnly = true)
  public ResponseEntity<Page<User>> getAll(
      @RequestParam(required = false, defaultValue = "0") int pageNumber,
      @RequestParam(required = false, defaultValue = "10") int pageSize) {
    return ResponseEntity.ok(UserService.getUsers(pageNumber, pageSize));
  }

  @GetMapping(path = "/{id}")
  @ApiOperation(value = "Get User by ID")
  @Transactional(readOnly = true)
  @ApiResponses({
    @ApiResponse(code = 200, message = "OK", response = User.class),
    @ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
    @ApiResponse(code = 404, message = "Not Found", response = Error.class),
    @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
  })
  public ResponseEntity<?> get(@PathVariable("id") final UUID id) {

    return UserService.get(id)
        .map(ResponseEntity::ok)
        .map(ResponseEntity.class::cast)
        .orElse(
            ResponseEntity.status(NOT_FOUND).body(new Error(format(USER_NOT_FOUND_MESSAGE, id))));
  }
  
  @GetMapping
  @ApiOperation(value = "Get User by Email Address")
  @Transactional(readOnly = true)
  @ApiResponses({
    @ApiResponse(code = 200, message = "OK", response = User.class),
    @ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
    @ApiResponse(code = 404, message = "Not Found", response = Error.class),
    @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
  })
  public ResponseEntity<?> get(@RequestParam("email") final String email) {

    return UserService.get(email)
        .map(ResponseEntity::ok)
        .map(ResponseEntity.class::cast)
        .orElse(
            ResponseEntity.status(NOT_FOUND).body(new Error(format(USER_NOT_FOUND_MESSAGE, email))));
  }

以上在编译时失败并Ambiguous mapping. Cannot map 'userController' method出现错误。本质上getAll()get(@RequestParam("email") final String email)具有相同的 URL 路径 - /users.

第二个是:

  @GetMapping
  @ApiOperation(value = "List all Users")
  @ApiResponses({
    @ApiResponse(code = 200, message = "OK", response = User.class, responseContainer = "List"),
    @ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
    @ApiResponse(code = 404, message = "Not Found", response = Error.class),
    @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
  })
  @Transactional(readOnly = true)
  public ResponseEntity<Page<User>> getAll(
      @RequestParam(required = false, defaultValue = "0") int pageNumber,
      @RequestParam(required = false, defaultValue = "10") int pageSize) {
    return ResponseEntity.ok(UserService.getUsers(pageNumber, pageSize));
  }

  @GetMapping(path = "/{id}")
  @ApiOperation(value = "Get User by ID")
  @Transactional(readOnly = true)
  @ApiResponses({
    @ApiResponse(code = 200, message = "OK", response = User.class),
    @ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
    @ApiResponse(code = 404, message = "Not Found", response = Error.class),
    @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
  })
  public ResponseEntity<?> get(@PathVariable("id") final UUID id) {

    return UserService.get(id)
        .map(ResponseEntity::ok)
        .map(ResponseEntity.class::cast)
        .orElse(
            ResponseEntity.status(NOT_FOUND).body(new Error(format(USER_NOT_FOUND_MESSAGE, id))));
  }
  
  @GetMapping(path = "/{email}")
  @ApiOperation(value = "Get User by Email Address")
  @Transactional(readOnly = true)
  @ApiResponses({
    @ApiResponse(code = 200, message = "OK", response = User.class),
    @ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
    @ApiResponse(code = 404, message = "Not Found", response = Error.class),
    @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
  })
  public ResponseEntity<?> get(@PathVariable("email") final String email) {

    return UserService.get(email)
        .map(ResponseEntity::ok)
        .map(ResponseEntity.class::cast)
        .orElse(
            ResponseEntity.status(NOT_FOUND).body(new Error(format(USER_NOT_FOUND_MESSAGE, email))));
  }

在这里,我遇到了控制器无法解决的问题,get(@PathVariable("email") final String emailget(@PathVariable("id") final UUID id)出现以下错误:

Ambiguous handler methods mapped for '/api/gems/users/fireball%40email.com': {public org.springframework.http.ResponseEntity com.personal.project.controllers.UserController.get(java.util.UUID), public org.springframework.http.ResponseEntity com.personal.project.controllers.UserController.get(java.lang.String)}

标签: javaspringspring-bootapirest

解决方案


您可以通过将这两个歧义路径合并为一个来解决它。对于第一种情况:

  @GetMapping
  @ApiOperation(value = "List all Users")
  @ApiResponses({
    @ApiResponse(code = 200, message = "OK", response = User.class, responseContainer = "List"),
    @ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
    @ApiResponse(code = 404, message = "Not Found", response = Error.class),
    @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
  })
  @Transactional(readOnly = true)
  public ResponseEntity<?> getUsers(
      @RequestParam(required = false, defaultValue = "0") int pageNumber,
      @RequestParam(required = false, defaultValue = "10") int pageSize,
// add email as param.
      @RequestParam(required = false) String email,

) {
    if(email ==null || StringUtils.isEmpty(email)){
       return ResponseEntity.ok(UserService.getUsers(pageNumber, pageSize));
    }else return UserService.get(email)
        .map(ResponseEntity::ok)
        .map(ResponseEntity.class::cast)
        .orElse(
            ResponseEntity.status(NOT_FOUND).body(new Error(format(USER_NOT_FOUND_MESSAGE, email))));
  }

对于第二个:

 // change the type UUID id to string.
  @GetMapping(path = "/{id}")
  ...
  public ResponseEntity<?> get(@PathVariable("id") final String id) {
    // check if id as an uuid or email, and based on that take action
  }

推荐阅读