对spring-boot-rest相当陌生,对如何以及如何使用该服务处理对客户端的响应有疑问。目前,我有以下控制器代码来处理在数据库查询中找不到记录的情况:
@PreAuthorize("hasAuthority('ROLE_USER')")
@GetMapping("distance/{id}")
public ResponseEntity<?> getDistanceById(@PathVariable("id") Integer id) {
log.info("getDistanceById");
Distance distance = distanceService.getDistanceById(id);
if (distance == null){
return new ResponseEntity<CustomErrorMsg>(new CustomErrorMsg("Distance ID " + id + " Not Found"),HttpStatus.NOT_FOUND);
}
return new ResponseEntity<Distance>(distance, HttpStatus.OK);
}
其中CustomErrorMsg是一个简单的类,它在构造函数中设置一个String。
这是最好的方法吗?基于ControllerAdvice的课程会是一个更好的方法吗?问这个问题是因为上面的代码在未经许可的情况下被cient调用时会发送预期的403响应。我想了解这种情况是如何发生的,以及它是否可以用于NOT FOUND条件。
"找不到资源"是一个众所周知的用例,对此您不必"麻烦"ResponseEntity或ControllerAdvice。您可以简单地使用ResourceNotFoundException。
@PreAuthorize("hasRole('USER')")
@GetMapping("distance/{id}")
public Distance getDistanceById(@PathVariable("id") Integer id) {
log.info("getDistanceById");
Distance distance = distanceService.getDistanceById(id);
if (distance == null) {
throw new ResourceNotFoundException("Distance ID " + id + " Not Found");
}
return distance;
}
将ResponseEntity<?>
声明为返回类型是正确的,但不会传递太多信息,因为您将实际数据和错误消息放在同一级别上。如果像我一样,你更喜欢使用ResponseEntity静态生成器,请访问:
@PreAuthorize("hasRole('USER')")
@GetMapping("distance/{id}")
public ResponseEntity<Distance> getDistanceById(@PathVariable("id") Integer id) {
log.info("getDistanceById");
Distance distance = distanceService.getDistanceById(id);
if (distance == null){
throw new ResourceNotFoundException("Distance ID " + id + " Not Found");
}
return new ResponseEntity.ok(distance);
}
同样,您感兴趣的是Distance(您的代码可能位于一个名为DistanceController
的类中),所以当没有找到它时,我们不要强调它。
现在,关于HTTP状态。如果您在权限不足的情况下请求/distance/<id>
,您将获得访问拒绝(403 Forbidden),这与未知资源(404 not Found)不同,也就是说,抛出ResourceNotFoundException时返回的状态。
在这里,首先检查访问请求的URL的权限。如果用户的身份验证权限不足,则会出现403错误。否则,您可以自由使用,并且将获得请求的资源(200),除非它不存在(404)。
我建议使用RestControllerAdvice注释类(例如名为GlobalExceptionHandler)来处理错误情况。当距离为null时,您需要更改getDistanceById方法以引发自定义异常。您需要向GlobalExceptionHandler添加一个方法,该方法将处理您的自定义异常。然后您可以将代码更改为以下内容:
@PreAuthorize("hasAuthority('ROLE_USER')")
@GetMapping("distance/{id}")
public ResponseEntity<Distance> getDistanceById(@PathVariable("id") Integer id) {
log.info("getDistanceById");
return ResponseEntity.ok(distanceService.getDistanceById(id));
}