Откат транзакции в Spring @Controller и отображение сообщения об исключении - PullRequest
1 голос
/ 13 февраля 2012

У меня есть контроллер Spring MVC, и когда возникает исключение, я хотел бы показать сообщение об исключении в представлении и откатить открытые транзакции.Представление содержит такую ​​форму:

<form:form method="POST" modelAttribute="registrationForm">
    <form:errors path="*" cssClass="error-message"/>
    ...
</form:form>

Я хотел бы показать сообщение об исключении в представлении, используя функцию <form:errors ... />.Это мое настоящее довольно ужасное решение:

@RequestMapping(value = "/registration", method = RequestMethod.POST)
public ModelAndView submitForm(@ModelAttribute("registrationForm") RegistrationForm registrationForm,
                         BindingResult result,
                         ModelAndView modelAndView,
                         HttpServletRequest request) throws Exception
{
    registrationValidator.validate(registrationForm, result);

    if(result.hasErrors())
    {
        return setupForm(modelAndView, registrationForm);
    }
    else
    {
        try
        {
            // ... Some non-transactional operations...

            // The following operation is the only one annotated with @Transactional
            // myExampleDao is @Autowired, can throw exception
            myExampleDao.createFoo(bar);

            // ... Other non-transactional operations...

            return new ModelAndView("redirect:successful");
        }
        catch(Exception e)
        {
            throw new RegistrationException(e, registrationForm, result);
        }
    }
}

@ExceptionHandler(value = RegistrationException.class)
public ModelAndView registrationExceptionHandler(RegistrationException e) throws Exception
{
    RegistrationForm registrationForm = e.getRegistrationForm();
    BindingResult result = e.getBindingResult();

    result.reject("exception", e.getMessage());
    Map<String, Object> model = result.getModel();
    return setupForm(new ModelAndView("registration", model), registrationForm);
}

private ModelAndView setupForm(ModelAndView modelAndView, RegistrationForm registrationForm) throws Exception
{
    Map<String,Object> model = modelAndView.getModel();
    model.put("currentYear", Calendar.getInstance().get(Calendar.YEAR));
    return new ModelAndView("registration", model);
}

Проблема, с которой я сталкиваюсь, заключается в том, что при возникновении исключения транзакция не откатывается.

Кто-нибудь может помочь?

Спасибо.

Обновление: немного изменил вопрос для лучшего понимания

Обновление: нашел довольно ужасное решение для отображениясообщение об исключении в представлении.По-прежнему сталкиваюсь с проблемой транзакции, которая не откатывается при возникновении исключения.

Обновление: Я изменил @Transactional на @Transactional(rollbackFor = Exception.class) в методе MyExampleDao.createFoo(...) и теперь всеработает отлично.Это решение все еще уродливое ИМО, у кого-нибудь есть лучшее решение?

Ответы [ 3 ]

3 голосов
/ 13 февраля 2012

Нет транзакций в ваших контроллерах. Поместите их в свой слой обслуживания.

Вы можете создать абстрактный класс контроллера, который реализует обработку исключений следующим образом (тогда каждый отдельный контроллер явно расширяется):

public class AbstractCtrl {

    @Resource(name = "emailService")
    private EmailService emailService;

    /*
     * Default exception handler, catchs all exceptions, redirects to friendly
     * error page and send e-mail does not catch request mapping errors
     */

    @ExceptionHandler(Exception.class)
    public String myExceptionHandler(final Exception e) {
    final StringWriter sw = new StringWriter();
    final PrintWriter pw = new PrintWriter(sw);
    e.printStackTrace(pw);
    final String strStackTrace = sw.toString(); // stack trace as a string
    emailService.sendAlertMail(strStackTrace);

    return "exception"; // default friendly excpetion message for user
    }
}

Но НЕ помещайте транзакции в свои контроллеры, поместите их в классы сервисного уровня.

0 голосов
/ 25 сентября 2012

Единственный способ управлять транзакцией в области контроллера - открыть сеанс из sessionFactory.

    Session session = sessionFactory.openSession();
try{
Transaction tx = session.beginTransaction();
    // code

session.save(foo);


tx.commit();
}catch(Exception e){
tx.rollback();
}finally{

try{session.close();}finally{}

}
0 голосов
/ 18 февраля 2012

Никто не предложил лучшего решения, чем мой уродливый.Вот мое решение, которое решило проблему, с которой я столкнулся:

@RequestMapping(value = "/registration", method = RequestMethod.POST)
public ModelAndView submitForm(@ModelAttribute("registrationForm") RegistrationForm registrationForm,
                         BindingResult result,
                         ModelAndView modelAndView,
                         HttpServletRequest request) throws Exception
{
    registrationValidator.validate(registrationForm, result);

    if(result.hasErrors())
    {
        return setupForm(modelAndView, registrationForm);
    }
    else
    {
        try
        {
            // ... Some non-transactional operations...

            // The following operation is the only one annotated with @Transactional
            // myExampleDao is @Autowired, can throw exception
            myExampleDao.createFoo(bar);

            // ... Other non-transactional operations...

            return new ModelAndView("redirect:successful");
        }
        catch(Exception e)
        {
            throw new RegistrationException(e, registrationForm, result);
        }
    }
}

@ExceptionHandler(value = RegistrationException.class)
public ModelAndView registrationExceptionHandler(RegistrationException e) throws Exception
{
    RegistrationForm registrationForm = e.getRegistrationForm();
    BindingResult result = e.getBindingResult();

    result.reject("exception", e.getMessage());
    Map<String, Object> model = result.getModel();
    return setupForm(new ModelAndView("registration", model), registrationForm);
}

private ModelAndView setupForm(ModelAndView modelAndView, RegistrationForm registrationForm) throws Exception
{
    Map<String,Object> model = modelAndView.getModel();
    model.put("currentYear", Calendar.getInstance().get(Calendar.YEAR));
    return new ModelAndView("registration", model);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...