抛出HTTP运行时异常的位置

时间:2015-11-03 19:01:55

标签: java spring

我们说我有以下运行时异常:

@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无关的上下文中使用该服务。

我会选择第二个。

您怎么看?

1 个答案:

答案 0 :(得分:3)

我同意你的上一次发言。您的服务层应独立于HTTP或frontent框架(@ResponseStatus是Spring MVC注释,因此在服务层中使用它不是最佳实践。)

但是,您不必在服务层中抛出一个异常,在控制器中捕获它并重新抛出另一个使用@ResponseStatus(HttpStatus.EXPECTATION_FAILED) @ExceptionHandler(InvalidInputParameters.class) public void handle() { // Do nothing, just return the status } 注释的异常。只需为服务异常添加异常处理程序并从中返回适当的响应状态。您有很多选择,例如@ExceptionHandler

select sum(months)
from (select t.*, 
         @time := if(@sum = 0, 0, period_diff(date_format(start_date, '%Y%m'), date_format(@prevtime, '%Y%m'))) as months,
         @prevtime := start_date,
         @sum := @sum + isstart
  from ((select start_date, 1 as isstart
         from position t
        ) union all
        (select end_date, -1
         from position t
        )
       ) t cross join
       (select @sum := 0, @time := 0, @prevtime := 0) vars 
  order by 1, 2
 ) t

您可以将此代码放到@ControllerAdvice带注释的类中,以便为所有控制器启用它,或者只在您的控制器中启用它,如果在其他地方不需要它。