Java 服务中引发异常时的Spring引导异常处理程序
我正在使用ControllerAdvice处理spring引导应用程序中的异常Java 服务中引发异常时的Spring引导异常处理程序,java,spring,spring-boot,exception,Java,Spring,Spring Boot,Exception,我正在使用ControllerAdvice处理spring引导应用程序中的异常 @Order(Ordered.HIGHEST_PRECEDENCE) @ControllerAdvice public class ErrorApiHandler extends ResponseEntityExceptionHandler { final ResponsesHelper rh; public ErrorApiHandler(ResponsesHelper rh) {
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class ErrorApiHandler extends ResponseEntityExceptionHandler {
final
ResponsesHelper rh;
public ErrorApiHandler(ResponsesHelper rh) {
this.rh = rh;
}
@ExceptionHandler(UsernameNotFoundException.class)
public ResponseEntity<Object> handleUsernameNotFoundException(UsernameNotFoundException ex) {
log.error(ExceptionUtils.getStackTrace(ex));
var error = buildError(ex);
return rh.buildResponse(error, HttpStatus.NOT_FOUND);
}
...
}
@顺序(有序。最高优先级)
@控制器建议
公共类ErrorApiHandler扩展了ResponseEntityExceptionHandler{
最终的
响应帮助rh;
公共错误处理程序(ResponseHelper rh){
这个。相对湿度=相对湿度;
}
@ExceptionHandler(UsernameNotFoundException.class)
公共响应handleUsernameNotFoundException(UsernameNotFoundException ex){
log.error(ExceptionUtils.getStackTrace(ex));
var错误=构建错误(ex);
返回rh.buildResponse(错误,HttpStatus.NOT_FOUND);
}
...
}
它可以很好地处理控制器中抛出的异常。
但是,如果抛出异常,例如在服务中,则不会执行ControllerAdvice
@Service
public class CustomUserDetailsService implements UserDetailsService {
final
UserRepository userRepository;
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
@Transactional
public User loadUserByUsername(String email)
throws UsernameNotFoundException {
log.debug(String.format("Loading user %s", email));
User user = userRepository.findByEmail(email)
.orElseThrow(() -> {
log.debug(String.format("User %s not found", email));
return new UsernameNotFoundException("User not found : " + email); // <- This exception is not handled.
});
log.debug(String.format("User %s loaded", user));
return user;
}
@服务
公共类CustomUserDetailsService实现UserDetailsService{
最终的
用户存储库用户存储库;
公共CustomUserDetailsService(用户存储库用户存储库){
this.userRepository=userRepository;
}
@凌驾
@交易的
公共用户loadUserByUsername(字符串电子邮件)
抛出UsernameNotFoundException{
log.debug(String.format(“正在加载用户%s”,电子邮件));
User=userRepository.findByEmail(电子邮件)
.orElseThrow(()->{
log.debug(String.format(“未找到用户%s”,电子邮件));
返回新的UsernameNotFoundException(“未找到用户:+电子邮件”);//@ControllerAdvice
用于处理通过控制器方法传播的异常(从控制器方法调用中抛出的异常-包括冒泡异常)所以,每当您直接在控制器方法中抛出异常,或者控制器方法正在调用的东西抛出异常时,都会尝试通过建议来处理它
如果您希望在web上下文之外以类似的方式(以某种方式)处理您的异常,您必须编写自己的方面,将所有内容包装为try catch,并允许您处理异常。我在ResponseEntityExceptionHandler文档中发现了这一点:
为@ControllerAdvice类提供了一个方便的基类,这些类希望通过@ExceptionHandler方法跨所有@RequestMapping方法提供集中的异常处理
扩展该类的自定义异常处理程序似乎只处理控制器层中的异常
我发现-使用HandlerExceptionResolver的解决方案听起来像是您正在寻找的解决方案。在我的例子中,我的“CustomUserDetailsService”是在筛选器中调用的:
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenProvider tokenProvider;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
UUID userId = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
...
我通过捕捉异常来处理它:
catch (UsernameNotFoundException ex){
log.error(ExceptionUtils.getStackTrace(ex));
var apiError = ErrorApiHandler.buildError(
new ResourceAlreadyTakenException(ex.getMessage())
);
response.addHeader("Content-Type", "application/json");
response.setStatus(HttpStatus.BAD_REQUEST.value());
PrintWriter writer = response.getWriter();
writer.write(convertObjectToJson(apiError));
writer.flush();
return;
}
理想情况下,使用控制器建议处理所有异常,但这样它就可以工作了我们谈论的是链式REST->WebController->Service->Exception吗?这是否有帮助: