简体   繁体   English

Spring Boot @ControllerAdvice + @Transactional 没有按预期工作

[英]Spring Boot @ControllerAdvice + @Transactional not working as expected

I'm working on a bets website so transactions are very important.我在一个投注网站上工作,所以交易非常重要。 I created an ExceptionHandler using @ControllerAdvice to catch all the exceptions from business layer.我使用@ControllerAdvice创建了一个 ExceptionHandler 来捕获业务层的所有异常。

@ControllerAdvice
public class HttpExceptionHandler {

  private String getStackTrace(final Throwable throwable) {
    final StringWriter stringWriter = new StringWriter()
    final PrintWriter printWriter = new PrintWriter(stringWriter, true)
    throwable.printStackTrace(printWriter)
    stringWriter.getBuffer().toString()
  }

  private List<String> filterStackTrace(final String stackTrace) {
    def stack = stackTrace.split('\n\t')
    stack.findAll({ it.contains('com.dsindigo.trading') })
  }

  private ResponseEntity<HttpErrorResponse> buildResponse(final Exception ex, final String message) {
    HttpErrorResponse error = new HttpErrorResponse(
      stack: filterStackTrace(getStackTrace(ex)),
      message: message
    )

    new ResponseEntity<HttpErrorResponse>(error, HttpStatus.BAD_REQUEST)
  }

  @ExceptionHandler(UsernameAlreadyExistsException)
  ResponseEntity<HttpErrorResponse> catchUsernameAlreadyExists(final UsernameAlreadyExistsException ex) {
    buildResponse(ex, HttpErrorMessages.USERNAME_ALREADY_EXISTS)
  }

  @ExceptionHandler(EmailAlreadyExistsException)
  ResponseEntity<HttpErrorResponse> catchEmailAlreadyExists(final EmailAlreadyExistsException ex) {
    buildResponse(ex, HttpErrorMessages.EMAIL_ALREADY_EXISTS)
  }

  //More exceptions...

  @ExceptionHandler(Exception)
  ResponseEntity<HttpErrorResponse> catchAny(final Exception ex) {
    buildResponse(ex, HttpErrorMessages.UNKNOWN)
  }
}

So basically it catches an exception (eg. UsernameAlreadyExistsException ) and creates a JSON response containing a custom message and the stacktrace (for debugging purposes).所以基本上它会捕获一个异常(例如UsernameAlreadyExistsException )并创建一个包含自定义消息和堆栈跟踪(用于调试目的)的 JSON 响应。

This is an example of a service throwing custom exceptions:这是抛出自定义异常的服务示例:

@Service
class UserServiceImpl implements UserService {

  // @Autowired stuff ...

  @Override
  @Transactional
  UserDTO save(UserDTO user) {
    UserDTO current = findOneByUsername(user.username)

    if (current != null)
      throw new UsernameAlreadyExistsException()

    current = findOneByEmail(user.email)

    if (current != null)
      throw new EmailAlreadyExistsException()

    ConfigurationDTO configuration = configurationService.findOne();

    user.active = false
    user.password = bCryptPasswordEncoder.encode(user.password)
    user.balance = configuration.initialBalance

    User entity = mapper.map(user, User)
    entity = userRepository.save(entity)
    user = mapper.map(entity, UserDTO)

    transactionService.createForUser(user.id, INITIAL_CHIPS_ID, configuration.initialBalance)

    TokenDTO token = tokenService.createForUser(user.id)
    emailService.sendRegisterMessage(user.email, token.token)

    user
  }
}

The problem is, when I throw a custom exception without @Transactional the exception handler executes the right method but adding @Transactional always executes the general Exception method.问题是,当我在没有@Transactional的情况下抛出自定义异常时,异常处理程序执行正确的方法,但添加@Transactional总是执行一般的Exception方法。

Am I missing something?我错过了什么吗?

These declarations:这些声明:

@ExceptionHandler(UsernameAlreadyExistsException)

Should be like this:应该是这样的:

@ExceptionHandler(UsernameAlreadyExistsException.class)

Also, make sure that your exceptions are extending RuntimeException.另外,请确保您的异常扩展了 RuntimeException。 If the exception is caught and handled anywhere else in your code (including Spring's interceptors!) it won't be handled by ControllerAdvice.如果异常在代码中的任何其他地方被捕获和处理(包括 Spring 的拦截器!),它不会被 ControllerAdvice 处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM