我有这个春季服务:
@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
我投入服务。我需要确定异常的类型,以便我可以提供自定义友好的用户消息。
答案 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() {
//
}
}
还有一些其他方法,请完整参考,请按照: