假设我有以下运行时异常:
@ResponseStatus(HttpStatus.EXPECTATION_FAILED)
public class ExpectationsFailedException extends RuntimeException {
public ExpectationsFailedException(String message) {
super(message);
}
}
我的问题是是否可以在我的服务层中抛出以前的 HTTP 异常,或者我应该从我的控制器中抛出它:
@Service
public class UserService {
@Autowired
...
public void addUser(final String email, final String username, final String password){
if(parameters_are_not_valid){
throw new ExpectationsFailedException("Invalid input");
}
}
}
控制器异常引发解决方案如下所示:
@Service
public class UserService {
@Autowired
...
public void addUser(final String email, final String username, final String password) throws InvalidInputParameters {
if(parameters_are_not_valid){
throw new InvalidInputParameters("Invalid input");
}
}
}
在我的控制器中
@RestController
public class XController{
@Autowired
private UserService userService;
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public void addUser(@Valid @RequestBody SignUpForm form, BindingResult bindingResult){
if(bindingResult.hasErrors()){
throw new ExpectationsFailedException("Input parameters conditions were not fulfilled");
}
try {
userService.addUser(...);
}
catch(InvalidInputParameters ex){
throw new ExpectationsFailedException("Invalid service input parameters");
}
}
}
这些解决方案中的哪一个是首选?为什么?我有一种感觉,我不应该在我的服务中抛出HTTP异常,因为我可能会在其他可能与HTTP无关的上下文中使用该服务。
我会选择第二个。
你觉得怎么样?
我同意你的最后一句话。您的服务层应该独立于HTTP或前端框架(@ResponseStatus
是Spring MVC注释,因此在服务层中使用它不是最佳实践(。
但是,您不必在服务层中抛出一个异常,在控制器中捕获它并重新抛出另一个用 @ResponseStatus
注释的异常。只需为服务异常添加异常处理程序,并从中返回适当的响应状态。您有很多选择,例如@ExceptionHandler
:
@ResponseStatus(HttpStatus.EXPECTATION_FAILED)
@ExceptionHandler(InvalidInputParameters.class)
public void handle() {
// Do nothing, just return the status
}
您可以将此代码放入带注释@ControllerAdvice
类中,以便为所有控制器启用它,或者仅在控制器中启用它(如果其他地方不需要它(。