我有这个春季服务:
@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 数据存储库:
@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
。我需要确定异常的类型,以便我可以提供自定义友好的用户消息。
你的DuplicatedCodeException,BusinessException应该是运行时异常,或者为方法saveBank添加:
@Transactinal(rolbackFor={BusinessException.class,DuplicatedCodeException.,class }(
在其他情况下,Spring 不会回滚事务。
来自 Spring 文档:
虽然 EJB 缺省行为是针对 EJB 容器 在系统异常时自动回滚事务(通常 运行时异常(,EJB CMT 不会回滚事务 在应用程序异常(即选中 java.rmi.RemoteException以外的异常(。虽然春天 声明式事务管理的缺省行为遵循 EJB 约定(仅在未选中的异常时自动回滚(,它 通常可用于自定义此内容。
只需在分支之前添加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;
}
发生这种情况是因为您的异常被包装在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 起可用
您也可以在@Controller
级别使用 @ExceptionHandler
,或者在抽象控制器中创建此处理(如果您将抽象控制器作为所有控制器的超类(。
public class FooController {
//...
@ExceptionHandler({ CustomException1.class, CustomException2.class })
public void handleException() {
//
}
}
还有其他一些方法,为了完整参考,请遵循:
SpringIO:Spring MVC 中的异常处理
Baeldung:使用弹簧进行异常处理