在 RestAPI Spring 应用程序中最佳使用 Optionals

Best use of Optionals in RestAPI Spring application

我对在我的 RestAPI Spring 应用程序中使用 Optionals 设计存储库 -> 服务 -> 控制器通信的方式感到有点困惑。 例如,客户想要通过 id 查找电影,但电影不存在并且存储库 returns 为空可选。我有两种处理方式:

  1. 服务方法returns 可选值或抛出可以在控制器中使用 ControllerAdvice 处理的异常。

  2. 服务 returns 可选,控制器处理它(return 值,如果存在或处理异常,或者可能只是做其他事情)。

我知道在这种简单的情况下使用异常不是最佳实践,您可能会建议其他方式让客户知道 id 错误。

目前 RestController 中的方法:

@GetMapping("/{id}")
public FilmGetDto getFilm(@PathVariable int id) {
    return filmService.getFilm(id);
}

如果你想向客户端发送一条关于不存在此类 ID 的消息,则必须处理此类边缘情况。 如果 optional.isPresent() returns false,您可能可以使用 Optional 和 handle,您可以发送自定义消息并让您的客户知道不存在具有此类 ID 的数据。

您可以使用包装器 class 来实现此目的。

class ErrorResponse {
  private String status;
  private int statusCode;
  private String message;

  public ErrorResponse(String status, int statusCode, String message){
      this.status = status;
      -----
      -----
   }
}

设置此字段和 return 此 class 对象作为响应。

我遵循或看到人们所做的大多数遵循的做法是您应该在服务中处理它并使用包装器 class 进行响应。通过这种方式,你将实现两件事,即你将拥有一个常量 Response 对象,你可以在你的所有应用程序中使用它,你也可以很容易地使用异常等。您应该始终以 MVC 状态处理服务层中任何寻求的业务逻辑。我在这里发布了一个示例,以便您可以更好地理解我在这里要说的内容。

控制器:

@GetMapping("/{id}")
public Response getFilm(@PathVariable int id) {
    return filmService.getFilm(id);
}

服务:

public Response getFilm(int id){
  Optional<Film> film = repo.findById(id);
  return film.map(f -> Response.builder().status(200).data(f).message("request  successful"))
             .orElseGet(() -> Response.builder().status(422).data(null).message("Film with given id not found");

}

和响应 class 也像@Adrash 建议的那样

class Response {
  private int status;
  private Object data;
  private String message;
   
  //you can use lombok or IDE  generate getter setters to generate getters setters
 }

注意:我已经使用lombok builder方法在服务层创建响应对象

你必须遵循标准,所以你不应该在控制器中编写代码,而应该在服务中编写代码,而且,你可以将你的响应包装在 class 中,提供适当的自定义消息,以便它对客户端有意义。正如@Adarsh 上面提到的 Wrapper class 你可以创建完全相同的,它会解决你的问题。并遵循@Danish 提到的标准。