我正在学习Spring Boot,当服务在数据库中找不到项目时,我试图抛出异常,因此,我尝试使用可选,但当我测试它时,除了异常之外,我只得到空响应
@GetMapping(value = "/compras", produces = "application/json")
public Optional<Compras> retrieveAllCompras(@RequestParam String id) {
return Optional.of(compraRepository.findById(id)).orElseThrow(RuntimeException::new);
当在数据库中找不到该项目时,我预计会出现异常
Optional.of
期望纯粹的价值。您也可以在文档中找到信息,
/**
* Constructs an instance with the described value.
*
* @param value the non-{@code null} value to describe
* @throws NullPointerException if value is {@code null}
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
例如,
jshell> Optional.of(100)
$2 ==> Optional[100]
jshell> Optional.of(null)
| Exception java.lang.NullPointerException
| at Objects.requireNonNull (Objects.java:221)
| at Optional.<init> (Optional.java:107)
| at Optional.of (Optional.java:120)
| at (#1:1)
如果您的值在运行时可能是
null
,您可以使用 .ofNullable
,
jshell> Optional.ofNullable(null)
$3 ==> Optional.empty
还有 函数式编程的思想是为所有输入返回一个值,而不是抛出破坏函数组合的
Exception
。
jshell> Function<Integer, Optional<Integer>> f = x -> Optional.of(x + 1)
f ==> $Lambda$23/0x0000000801171c40@6996db8
jshell> Function<Integer, Optional<Integer>> g = x -> Optional.of(x * 2)
g ==> $Lambda$24/0x0000000801172840@7fbe847c
jshell> f.apply(5).flatMap(x -> g.apply(x))
$13 ==> Optional[12]
因此,在您的示例中,您可以将
Optional.empty()
视为未找到的项目,但 Spring 也会将其视为 200
,这仍然比抛出 500
更好。 您可能希望发送 404
才能准确.
@GetMapping(
value = "/compras",
produces = "application/json"
)
public Optional<Compras> retrieveAllCompras(@RequestParam String id) {
return Optional.ofNullable(compraRepository.findById(id)); //will response as 200 even when no item found
}
ResponseEntity<A>
设置特定的 http 状态
传统的响应方式
404
是定义特定的异常。
import org.springframework.web.server.ResponseStatusException;
import org.springframework.http.HttpStatus;
@GetMapping(
value = "/compras",
produces = "application/json"
)
public Compras retrieveAllCompras(@RequestParam String id) {
return Optional.ofNullable(compraRepository.findById(id))
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "item not found"))
}
想想这里的类型,如果你想返回Optional,你会做一个
.orElse
,你必须再次包装它。这将是一种方法:
@GetMapping(value = "/compras", produces = "application/json")
public Optional<Compras> retrieveAllCompras(@RequestParam String id) {
return Optional.ofNullable(compraRepository.findById(id)).
map(Optional::of).
orElseThrow(() -> new RuntimeException("Not found"));
我来解释一下:
Optional.ofNullable()
将返回 Optional<Compras>
,其值为 Optional("some compras")
或值 Optional.Empty
map(Optional::of)
将再次包装可选,所以你将拥有Optional[Optional<Compras>]
或(这里是技巧)Optional.Empty,因为map不包装Optional.Empty(这就是他在我们中间的原因)orElseThrow(() -> new RuntimeException("Not found"))
将解压您的可选选项,在本例中从Optional[Optional<Compras>]
到Optional<Compras>
,或者,如果是Optional.Empty
,它将抛出异常您的控制器返回
Optional<Compras>
。这意味着不会调用 #get
方法。如果 Optional
值,您的控制器将返回 null。
更改为:
public Compras retrieveAllCompras...
,您将得到例外
从对象名称和调用的方法(
compraRepository.findById(id)
)来看,您的服务实际上是一个存储库。如果它是 Spring Data 存储库,那么您应该将 Optional
的创建留给 Spring Data:存储库方法的 Null 处理。这样你就会拥有
compraRepository.findById(id).orElseThrow(NotFoundException::new)
在我的例子中,我使用Optional类的isPresent()方法处理空响应:
@GetMapping("/{id}")
public ResponseEntity<TraineeDto> getById(@PathVariable int id) {
try {
Optional<TraineeDto> traineeDto = traineeService.findById(id);
if (traineeDto.isPresent()) {
return ResponseEntity.ok(traineeDto.get());
} else {
return ResponseEntity.notFound().build(); // 404 Not Found
}
} catch (DataNotFoundException ex) {
return ResponseEntity.notFound().build(); // 404 Not Found
} catch (Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); // 500 Internal Server Error
}
}