假设我开发了一些rest api。我有网络层(控制器)和服务层(模型)。在服务层抛出httpstatus代码异常是否是一个好的实践?
有人会说,那个模型不应该知道任何关于web层的东西,它不应该依赖于web层。
但是,让我们考虑一下这种情况:
在控制器中引发HttpStatus异常
---服务---
class userService {
public void updateUser(int userId, String username, String email) {
if ( //userid not found) {
throw new UserNotFoundException("User not found");
}
if ( // bad email format) {
throw new BadArgumentException("Bad email format");
}
if ( // user is not active) {
throw new AccessDeniedException("User is not active");
}
... here save user ...
}
}
---控制器---
class UserController {
@RequestMapping ....
public void updateUser(int id, String username, String email) {
try{
userService.updateUser(id, username, email);
}
catch (UserNotFoundException e) {
throw new HttpException(e.getMessage(), HttpStatus.NOT_FOUND);
}
catch (BadArgumentExceptione e) {
throw new HttpException(e.getMessage(), HttpStatus.BAD_REQUEST);
}
catch (AccessDeniedException e) {
throw new HttpException(e.getMessage(), HttpStatus.FORBIDEN);
}
}
}
你看到了吗?我应该编写多少额外的代码才能向api客户端返回正确的响应?另外,我可以忘记捕获一些可以正确报告的异常,它将作为默认的内部服务器异常返回。在controller中,我总是应该查看服务层并检查哪些异常可以抛出服务来正确处理它们。(请不要在Java中建议检查异常)。
现在让我们看看另一个解决方案:
在服务层(模型)中引发HttpStatus异常
---服务---
类用户服务{
public void updateUser(int userId, String username, String email) {
if ( //userid not found) {
throw new UserNotFoundException("User not found", HttpStatus.NOT_FOUND);
}
if ( // bad email format) {
throw new BadArgumentException("Bad email format", HttpStatus.BAD_REQUEST);
}
if ( // user is not active) {
throw new AccessDeniedException("User is not active", HTTP_STATUS.FORBIDEN);
}
... here save user ...
}
}
--控制器--
class UserController {
@RequestMapping ....
public void updateUser(int id, String username, String email) {
userService.updateUser(id, username, email);
}
}
就这样。更少的代码。现在,我不必处理每一个可能抛出服务层的异常,也不必在每次编写控制器时手动检查服务异常,而且我不会忘记处理一些异常(因为它们在服务层中的格式正确),这样就不容易出错。
再说一遍,在服务层处理与http相关的数据是不是不好?
如果情况不好,你将如何处理我所描述的问题。
谢谢您。
注意:在这两种解决方案中,一些通用的errorhandler捕捉异常并用适当的状态码形成响应。
最佳答案
您可以在控制器内的方法中使用@exceptionhandler来管理同一控制器中的异常
@ExceptionHandler({MyException.class,OtherException.class})
public String myMethodExceptionHandler() {...}
或者您可以使用@controlleradvice创建一个类来管理所有控制器的错误
@ControllerAdvice
class GlobalControllerExceptionHandler {
@ResponseStatus(HttpStatus.CONFLICT) // 409
@ExceptionHandler(MyException.class)
public void handleConflict() {
// Nothing to do
}
}
这里有一个教程。
https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc