调用 API 时如何逃避空值检查?

How can I escape null check when call a API?

当我在 Spring 中编写 RestController 时,我总是检查对象是否为 null。我怎样才能逃过这个检查?

在下面的示例中,有空检查和后来的 return notFound 或 Http 状态 404。所以我不想一直检查它。

  @GetMapping(path = "/api/member/{member-id}")
  public ResponseEntity<Member> getMemberById(@PathVariable(name="member-id", required=true) final Long memberId) {
    final Member member = memberService.findById(memberId);
    if (member != null) {
      return ResponseEntity.ok(member);
    }
    return ResponseEntity.notFound().build();
  }

很好。

或者,memberService.findById 可以 return 和 Optional<Member> 代替,然后您可以执行以下操作:

memberService.findById(memberId)
  .map(it -> ResponseEntity.ok(member).build())
  .orElse(ResponseEntity.notFound().build());

您还可以 "encode" 异常类型中的 return 类型,每当您在数据库 tier/layer 中搜索请求的资源时,如果不存在,您可以抛出它被翻译成 HTTP Not Found 下游的异常——在一些异常处理程序中。在那种情况下,您无需担心控制器中的不同 return 类型——但所有这些魔法也有一些缺点,例如,它不太清楚(对于新手)发生了什么只需检查代码,除非您已经研究了一段时间。

此外,如果您不想重复相同的 null 检查,您可以将其包装在 generic/common 方法中。

虽然您无法避免 null 检查本身,但您可以将其从 Controller 移出到服务中(同样,使用 Optional)。如果您正在寻找处理负面响应场景的通用策略,我建议使用 Spring 的 RestControllerAdvice 注释,这将为您的所有 API 启用全局异常处理:

让我们首先将检查移至服务并引发自定义异常 MemberNotFoundException 以防未找到记录。

DefaultMemberService.java

public Member findById(final String memberId) {
  Optional<Member> member = memberRepository.findById(memberId);
  return member.orElseThrow(() -> new MemberNotFoundException("Invalid member Id"));
}

在控制器中,只需调用服务方法,然后return响应。

MemberController.java

@GetMapping(path = "/api/member/{member-id}")
public ResponseEntity<Member> getMemberById(@PathVariable(name="member-id", required=true) final Long memberId) {

  return ResponseEntity.ok().body(memberService.findById(memberId));
}

如您所见,我们没有显式处理异常。相反,我们将通过将异常 class 映射到响应(错误消息、响应代码)来让 RestControllerAdvice 为我们做这件事:

ExceptionHandlerControllerAdvice.java

@RestControllerAdvice
public final class ExceptionHandlerControllerAdvice {

  @ExceptionHandler({ MemberNotFoundException.class })
  @ResponseStatus(HttpStatus.NOT_FOUND)
  ResponseEntity<ErrorDto> handleRecordNotFound(MemberNotFoundException ex) {
    return ResponseEntity.status(HttpStatus.NOT_FOUND)
        .body(new ErrorDto(ex.getMessage));
  }
}

其中,ErrorDto(简体)是:

public class ErrorDto {
  private String message;

  public ErrorDto(String msg) { this.message = msg; }

  public String getMessage() { return this.message; }
}

参考:RestControllerAdvice, ExceptionHandler