2017-06-15 63 views
1

我有這個春季服務:如何從事務性的Spring服務中拋出自定義異常?

@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); 
     } 
    } 


} 

該服務使用這個春天數據倉庫:

@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我投入服務。我需要確定異常的類型,以便我可以提供自定義友好的用戶消息。

回答

0

也你DuplicatedCodeException,BusinessException應該運行時異常,或添加方法saveBank:

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

在其他情況下spring不會回滾事務。

EJB的默認行爲是EJB容器 在遇到系統異常(通常 運行時異常)時自動回滾事務,EJB CMT不會回滾:

從Spring文檔

事務 自動應用程序異常(即,檢查 異常而不是java.rmi.RemoteException)。雖然聲明式事務管理的默認行爲遵循EJB 約定(回滾僅在未經檢查的例外情況下自動回滾),但 通常用於自定義此操作。

+0

我從'RuntimeException',而不是'Exception'繼承和行爲是爲我預期。 –

1

只需在catch (Exception e)分支之前加catch (TransactionSystemException tse)分支,然後用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; 
} 
0

那是因爲你的異常被包裹在RollbackExceptionThrowable原因。輪到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可用,因爲春季3.2

您也可以在@Controller級別使用@ExceptionHandler,或創建此在抽象控制器中處理,如果你有一個作爲所有控制器的超類。

public class FooController { 

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

還有一些其他的辦法,完全參考,請遵循:

Spring IO: Exception handling in Spring MVC

Baeldung: Exception handling with Spring