如何从事务Spring服务中抛出自定义异常?

时间:2017-06-15 19:37:38

标签: java spring spring-mvc jpa

我有这个春季服务:

@Service
@Transactional
public class ConsorcioServiceImpl implements ConsorcioService {

    ...

    @Autowired
    private ConsorcioRepository consorcioRepository;

    @Override
    public void saveBank(Consorcio consorcio) throws BusinessException {

        try {
            consorcioRepository.save(consorcio);
        }
        catch(DataIntegrityViolationException divex) {
            if(divex.getMessage().contains("uq_codigo")) {
                throw new DuplicatedCodeException(divex);
            }
            else {
                throw new BusinessException(dives); 
            }
        }
        catch (Exception e) {
            throw new BusinessException(e);
        }
    }


}

该服务使用此Spring Data存储库:

@Repository
public interface ConsorcioRepository extendsCrudRepository<Consorcio, Integer> {


}

我正在从弹簧控制器调用该服务:

@Controller
@RequestMapping(value = "/bank")
public class BancaController {

    @Autowired
    private ConsorcioService consorcioService;

    @RequestMapping(value="create", method=RequestMethod.POST)
    public ModelAndView crearBanca(@Valid BancaViewModel bancaViewModel, BindingResult bindingResult,
                                   RedirectAttributes redirectAttributes) {
        ModelAndView modelAndView;

        MessageViewModel result;
        try {

            consorcioService.saveBank(bancaViewModel.buildBanca());
            result = new MessageViewModel(MessageType.SUCESS);
            redirectAttributes.addFlashAttribute("messageViewModel", result);
            modelAndView = new ModelAndView("redirect:/banca/crear");
            return modelAndView;
        } catch (Exception e) {
            result = new MessageViewModel(MessageType.ERROR);
            modelAndView = new ModelAndView("crear-bancas");
            modelAndView.addObject("messageViewModel", result);
            return modelAndView;
        }
}

但我在控制器中遇到的异常是:org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly 而不是DuplicatedCodeException我投入服务。我需要确定异常的类型,以便我可以提供自定义友好的用户消息。

3 个答案:

答案 0 :(得分:1)

只需在catch (TransactionSystemException tse)分支之前添加catch (Exception e),然后使用getOriginalException()提取您的例外。

try {
    consorcioService.saveBank(bancaViewModel.buildBanca());
    result = new MessageViewModel(MessageType.SUCESS);
    redirectAttributes.addFlashAttribute("messageViewModel", result);
    modelAndView = new ModelAndView("redirect:/banca/crear");
    return modelAndView;
} catch (TransactionSystemException tse) {
    final Throwable ex = tse.getOriginalException();
    if (ex instanceof DuplicatedCodeException) {
        // DuplicatedCodeException
    }
} catch (Exception e) {
    result = new MessageViewModel(MessageType.ERROR);
    modelAndView = new ModelAndView("crear-bancas");
    modelAndView.addObject("messageViewModel", result);
    return modelAndView;
}

答案 1 :(得分:0)

你的DuplicatedCodeException,BusinessException应该是运行时异常,或者为方法saveBank添加:

  

@Transactinal(rolbackFor = {BusinessException.class,DuplicatedCodeException。,class})

在其他情况下,spring不会回滚事务。

来自Spring文档的

  

虽然EJB默认行为是针对EJB容器的   在系统异常时自动回滚事务(通常   一个运行时异常),EJB CMT不会回滚事务   自动应用程序异常(即已检查的异常)   java.rmi.RemoteException以外的异常)。而春天   声明式事务管理的默认行为遵循EJB   约定(仅在未经检查的异常时自动回滚),它   通常对定制它很有用。

答案 2 :(得分:0)

这是因为您的异常被RollbackException包含在Throwable原因中。在它的转弯RollbackException也是TransactionSystemException的原因。

您可以构建全局异常处理程序来捕获和自定义所有异常:

@ControllerAdvice
class GlobalControllerExceptionHandler {
    @ResponseStatus(HttpStatus.CONFLICT) 
    @ExceptionHandler(TransactionSystemException.class)
    public ModelAndView handleDupilatedCode(HttpServletRequest req, TransactionSystemException ex) {
        // Build you exception body here
        Throwable e = ex.getOriginalException();
        if(e instanceof DuplicatedCodeException)
          // throw
        // Or build custom exception as you want
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", e);
        mav.addObject("url", req.getRequestURL());
        mav.setViewName("error");
        return mav;
    }
}

@ControllerAdvice自Spring 3.2起可用

此外,您可以在@ExceptionHandler级别使用@Controller,或者如果您有一个作为所有控制器的超类,则可以在abstract-controller中创建此处理。

public class FooController {

    //...
    @ExceptionHandler({ CustomException1.class, CustomException2.class })
    public void handleException() {
        //
    }
}

还有一些其他方法,请完整参考,请按照:

Spring IO: Exception handling in Spring MVC

Baeldung: Exception handling with Spring