Spring - Manage custom Exception page - spring

I'm trying to manage a custom error page with my custom exception.
I have this exception
#ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Inesistente")
public class ResourceNotAccessibleException extends Throwable{
public ResourceNotAccessibleException(String message){
super(message);
}
}
which i want to respond with a 404 error.
Than i'm managing an error controller
#ControllerAdvice
public class ErrorController {
#ExceptionHandler({ResourceNotAccessibleException.class})
public ModelAndView getErrorPage(HttpServletRequest request, Throwable ex) {
String errorMsg = "";
int httpErrorCode = getErrorCode(request);
switch (httpErrorCode) {
case 404: {
logger.error("Status Error " + httpErrorCode , ex.getMessage());
errorMsg = messageSource.getMessage("errorMessage", new Object[] { uuid, +httpErrorCode }, locale);
break;
}
case 400: {
errorMsg = "BAD REQUEST";
break;
}
case 500: {
errorMsg = messageSource.getMessage("errorMessage", new Object[] { uuid, +httpErrorCode }, locale);
logger.error("Status Error " + httpErrorCode , ex.getMessage());
break;
}
}
ModelAndView mav = new ModelAndView();
mav.addObject("errorMsg", errorMsg);
mav.setViewName("error");
return mav;
}
Now, in my controller if i have something like
if(object==null) {
throw new ResourceNotAccessibleException("Resource does not exist");
}
I should see my error view, but i'm getting the classic white error page, in my log i see the exception being hit..

The ResourceNotAccessibleException should extend Exception or RuntimeException and not Throwable. More info
If you can't change exception type, probably you could try ExceptionHandlerExceptionResolver or this awesome post about Spring exception handling
One more thing, you probably want to add some #ResponseStatus info above getErrorPage, because you are handling this exeption and #ResponseStatus annotation above the ResourceNotAccessibleException will never trigger.
So i think something like this should work:
#ControllerAdvice
public class ErrorController {
#ResponseStatus(value= HttpStatus.NOT_FOUND) // <= important
#ExceptionHandler({ResourceNotAccessibleException.class})
public ModelAndView getErrorPage(HttpServletRequest request, Throwable ex) {
String errorMsg = "";
// ... some code here
ModelAndView mav = new ModelAndView();
mav.addObject("errorMsg", errorMsg);
mav.setViewName("error");
return mav;
}
}
public class ResourceNotAccessibleException extends Exception{ // <= important
public ResourceNotAccessibleException(String message){
super(message);
}
}
If this doesn't work, you can also try to change resource view file name to something like errorPage.jsp or errorPage.html and set it like mav.setViewName("errorPage");

You need to replace the default error pages in your web container and map a status code to a particular error page.
Here are the changes you need to make:
If it's a Jetty container, here are the changes:
#Bean
public JettyEmbeddedServletContainerFactory
containerFactory(
#Value("${server.port:8080}") final String port,
#Value("${jetty.threadPool.maxThreads:600}") final String maxThreads,
#Value("${jetty.threadPool.minThreads:10}") final String minThreads,
#Value("${jetty.threadPool.idleTimeout:5000}") final String idleTimeout) {
final JettyEmbeddedServletContainerFactory factory =
new JettyEmbeddedServletContainerFactory(Integer.valueOf(port));
...
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/error-info.html"));
...
return factory;
}
If it's a Tomcat container, here are the changes:
#Bean
public EmbeddedServletContainerCustomizer container() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(
ConfigurableEmbeddedServletContainer container) {
container.addErrorPages(new
ErrorPage(HttpStatus.NOT_FOUND, "/error-info.html"));
}
};
}
For your ErrorController, don't set view name. It will pick the view from the error page mapping which was set earlier.
#ControllerAdvice
public class ErrorController {
#ExceptionHandler(ResourceNotAccessibleException.class)
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public ModelAndView handleResourceNotAccessibleException(
HttpServletRequest req, ResourceNotAccessibleException ex) {
...
ModelAndView mav = new ModelAndView();
mav.addObject("errorMsg", errorMsg);
retrun mav;
}
}
Location of error-info.html or jsp under resources/static

Related

Spring MVC, redirect to error after Rest call exception

I'm performing a Rest request in one of my controllers and I'd like to redirect to my error view if the request went wrong (404, 503 ...)
My controller calls this function :
public String functionTest(){
String date, res;
String url = "myRestUrl/{param}";
Map<String, String> uriParams = new HashMap<>();
uriParams.put("param", "param");
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url);
HttpEntity<String> request = new HttpEntity<>(createHeaders());
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new RestErrorHandler());
ResponseEntity<String> response = restTemplate.exchange(builder.buildAndExpand(uriParams).toUri(), HttpMethod.GET, request, String.class);
res= response.getBody().getMyResult();
return res;
}
And here is my Rest error handler :
public class RestErrorHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
//Here I need to use a ModelAndView to redirect to error view but I'm not anymore in my controller
}
}
I guess I'm doing it wrong, do you have any solutions ?
Here is a rather simplistic way to achieve what you need. If you would like more control/flexibility, refer to this Spring blog article.
In your (client) RestErrorHandler:
public class RestErrorHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response)
throws IOException {
// Do some stuff here ...
// This could be your own exception, for example.
throw new IOException();
}
}
Then in your controller (or refer to the article above if you want other options):
// Your requestMappings here ...
#ExceptionHandler(Exception.class)
public ModelAndView handleError(HttpServletRequest req, Exception ex) {
ModelAndView mav = new ModelAndView();
// Do stuff and redirect to your error view.
return mav;
}
EDIT: Another solution would be to catch Spring's RestClientException, which is a RuntimeException thrown by RestTemplate when it encounters an error:
try {
restTemplate.exchange(...);
} catch (RestClientException ex) {
// Do stuff here ...
}

Spring: Catch exception thrown from AccessDecisionManager - NOT from Controller

Using Spring (4.2.4) with MVC (4.2.4) and Security (4.0.3). I have implemented an AccessDecisionManager and from within my decide-method I am throwing an exception:
public void decide(
Authentication authentication,
Object object,
Collection<ConfigAttribute> configAttributes
) throws AccessDeniedException, InsufficientAuthenticationException {
FilterInvocation fi = (FilterInvocation) object;
String requestUrl = fi.getRequestUrl();
...
throw new SessionCompanyNotRoleTableCompanyException(1, 2);
...
throw new AccessDeniedException("Access denied!");
}
I'm not able to catch neither "SessionCompanyNotRoleTableCompanyException" nor AccessDeniedException. I've tried using a global exception handler:
#Component
#ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
#ExceptionHandler(SessionCompanyNotRoleTableCompanyException.class)
public ModelAndView sessionCompanyNotRoleTableCompany() {
log.debug("SessionCompanyNotRoleTableCompanyException captured in GlobalExceptionHandler");
String reason = "Reason: SessionCompanyNotRoleTableCompanyException";
ModelAndView mav = new ModelAndView();
mav.addObject("reason", reason);
mav.setViewName("error.html");
return mav;
}
#ExceptionHandler(Exception.class)
public ModelAndView exception(ModelMap model) {
log.debug("Exception captured in GlobalExceptionHandler");
String reason = "General Exception";
ModelAndView mav = new ModelAndView();
mav.addObject("reason", reason);
mav.setViewName("error.html");
return mav;
}
}
I've even created ExceptionResolver-classes like:
#Component
public class SessionCompanyNotRoleTableCompanyExceptionResolver implements HandlerExceptionResolver, Ordered {
private static final Logger log = LoggerFactory.getLogger(SessionCompanyNotRoleTableCompanyExceptionResolver.class);
private int order;
#Override
public ModelAndView resolveException(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex
) {
if (ex instanceof SessionCompanyNotRoleTableCompanyException) {
log.debug("SessionCompanyNotRoleTableCompanyException captured in SessionCompanyNotRoleTableCompanyExceptionResolver");
String reason = "Reason: SessionCompanyNotRoleTableCompanyException";
ModelAndView mav = new ModelAndView();
mav.addObject("reason", reason);
mav.setViewName("error.html");
return mav;
}
return null;
}
#Override
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}
... and have them initialized in my web-config-class like:
#Bean
public SessionCompanyNotRoleTableCompanyExceptionResolver createSessionCompanyNotRoleTableCompanyExceptionResolver() {
SessionCompanyNotRoleTableCompanyExceptionResolver resolver = new SessionCompanyNotRoleTableCompanyExceptionResolver();
resolver.setOrder(1);
return resolver;
}
These work, i.e. exceptions are captured ONLY IF they are thrown from the Controllers. But NOT from my decide-method in the AccessDecisionManager.
What and how am I supposed to implement something that can catch these outside (before) the controller?
EDIT (adding the SessionCompanyNotRoleTableCompanyException to show you its definition):
public class SessionCompanyNotRoleTableCompanyException extends RuntimeException {
private static final long serialVersionUID = 1L;
public SessionCompanyNotRoleTableCompanyException(Long contextCompanyId, Long tableId) {
super("Context companyId: " + contextCompanyId + ", tableId: " + tableId);
}
}

Multiple error pages from the same ExceptionHandler

In my current spring-boot project, I have this ExceptionHandler:
#ControllerAdvice
public class GlobalDefaultExceptionHandler {
#ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest request, Exception error) throws Exception {
if (AnnotationUtils.findAnnotation(error.getClass(), ResponseStatus.class) != null)
throw error;
ModelAndView mav = new ModelAndView();
mav.setAttribute("error", error);
return mav;
}
}
What I want to do it's make this handler redirect to different error pages, depending of origin the error.
I have two "types" of pages in my project: a public one, acessed both by an anonymous user or an authenticated user, and the admin pages (private), acessed only by authenticated users.
This two types of page have different styles. I want, when an error occurs when the user is in the public pages, an error page with the public style be shown. If the errors occurs when the user is in the private pages, another error page, with the style of the private pages be shown.
You can construct a selection of what exception classes it needs to throw in your controller , Assuming like this:
#RequestMapping(value = "/check")
public ModelAndView processUser( ) throws Exception {
ModelAndView modelAndView = new ModelAndView();
if (something... ) {
throw new GlobalDefaultExceptionHandler( ); // throws GlobalDefaultExceptionHandler
}
if (something else... ) {
throw new AnotherExceptionHandler( );// throws 'anotherExceptionHandler'
}
// If there isn't exception thrown....do something
}
And assuming this is the AnotherExceptionHandler class:
#ControllerAdvice
public class AnotherExceptionHandler{
#ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest request, Exception error) throws Exception {
if (AnnotationUtils.findAnnotation(error.getClass(), ResponseStatus.class) != null)
throw error;
// Go to another view
ModelAndView mav = new ModelAndView();
mav.setAttribute("anotherError", error);
return mav;
}
}
But if you are forced to use only an handler , you can just use selection directly just :
#ControllerAdvice
public class GlobalDefaultExceptionHandler {
#ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest request, Exception error) throws Exception {
ModelAndView mav =null;
if ( // something...){
mav = new ModelAndView()
mav.setAttribute("error", ... );
return mav;
}
else if (// another something...){
mav = new ModelAndView()
mav.setAttribute("anotherError", ...);
return mav;
}
return mav;
}
There are several options. Some of them are:
You can check if user has been authenticated by using request.getUserPrincipal(). The return value will be null if user is not authentcicated. Depending on the result, you can return a different view.
Have all your Contollers service public pages extend from one PublicBaseController and controllers service private pages extend PrivateBaseController. Add method annotated with #ExceptionHandler to base controllers, which return appropriate views.

Spring MVC - RestTemplate launch exception when http 404 happens

I have a rest service which send an 404 error when the resources is not found.
Here the source of my controller and the exception which send Http 404.
#Controller
#RequestMapping("/site")
public class SiteController
{
#Autowired
private IStoreManager storeManager;
#RequestMapping(value = "/stores/{pkStore}", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public StoreDto getStoreByPk(#PathVariable long pkStore) {
Store s = storeManager.getStore(pkStore);
if (null == s) {
throw new ResourceNotFoundException("no store with pkStore : " + pkStore);
}
return StoreDto.entityToDto(s);
}
}
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException
{
private static final long serialVersionUID = -6252766749487342137L;
public ResourceNotFoundException(String message) {
super(message);
}
}
When i try to call it with RestTemplate with this code :
ResponseEntity<StoreDto> r = restTemplate.getForEntity(url, StoreDto.class, m);
System.out.println(r.getStatusCode());
System.out.println(r.getBody());
I receive this exception :
org.springframework.web.client.RestTemplate handleResponseError
ATTENTION: GET request for "http://........./stores/99" resulted in 404 (Introuvable); invoking error handler
org.springframework.web.client.HttpClientErrorException: 404 Introuvable
I was thinking I can explore my responseEntity Object and do some things with the statusCode. But exception is launch and my app go down.
Is there a specific configuration for restTemplate to not send exception but populate my ResponseEntity.
As far as I'm aware, you can't get an actual ResponseEntity, but the status code and body (if any) can be obtained from the exception:
try {
ResponseEntity<StoreDto> r = restTemplate.getForEntity(url, StoreDto.class, m);
}
catch (final HttpClientErrorException e) {
System.out.println(e.getStatusCode());
System.out.println(e.getResponseBodyAsString());
}
RESTTemplate is quite deficient in this area IMO. There's a good blog post here about how you could possibly extract the response body when you've received an error:
http://springinpractice.com/2013/10/07/handling-json-error-object-responses-with-springs-resttemplate
As of today there is an outstanding JIRA request that the template provides the possibility to extract the response body:
https://jira.spring.io/browse/SPR-10961
The trouble with Squatting Bear's answer is that you would have to interrogate the status code inside the catch block eg if you're only wanting to deal with 404's
Here's how I got around this on my last project. There may be better ways, and my solution doesn't extract the ResponseBody at all.
public class ClientErrorHandler implements ResponseErrorHandler
{
#Override
public void handleError(ClientHttpResponse response) throws IOException
{
if (response.getStatusCode() == HttpStatus.NOT_FOUND)
{
throw new ResourceNotFoundException();
}
// handle other possibilities, then use the catch all...
throw new UnexpectedHttpException(response.getStatusCode());
}
#Override
public boolean hasError(ClientHttpResponse response) throws IOException
{
return response.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR
|| response.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR;
}
The ResourceNotFoundException and UnexpectedHttpException are my own unchecked exceptions.
The when creating the rest template:
RestTemplate template = new RestTemplate();
template.setErrorHandler(new ClientErrorHandler());
Now we get the slightly neater construct when making a request:
try
{
HttpEntity response = template.exchange("http://localhost:8080/mywebapp/customer/100029",
HttpMethod.GET, requestEntity, String.class);
System.out.println(response.getBody());
}
catch (ResourceNotFoundException e)
{
System.out.println("Customer not found");
}
Since it's 2018 and I hope that when people say "Spring" they actually mean "Spring Boot" at least, I wanted to expand the given answers with a less dust-covered approach.
Everything mentioned in the previous answers is correct - you need to use a custom ResponseErrorHandler.
Now, in Spring Boot world the way to configure it is a bit simpler than before.
There is a convenient class called RestTemplateBuilder. If you read the very first line of its java doc it says:
Builder that can be used to configure and create a RestTemplate.
Provides convenience methods to register converters, error handlers
and UriTemplateHandlers.
It actually has a method just for that:
new RestTemplateBuilder().errorHandler(new DefaultResponseErrorHandler()).build();
On top of that, Spring guys realized the drawbacks of a conventional RestTemplate long time ago, and how it can be especially painful in tests. They created a convenient class, TestRestTemplate, which serves as a wrapper around RestTemplate and set its errorHandler to an empty implementation:
private static class NoOpResponseErrorHandler extends
DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
}
}
You can create your own RestTemplate wrapper which does not throw exceptions, but returns a response with the received status code. (You could also return the body, but that would stop being type-safe, so in the code below the body remains simply null.)
/**
* A Rest Template that doesn't throw exceptions if a method returns something other than 2xx
*/
public class GracefulRestTemplate extends RestTemplate {
private final RestTemplate restTemplate;
public GracefulRestTemplate(RestTemplate restTemplate) {
super(restTemplate.getMessageConverters());
this.restTemplate = restTemplate;
}
#Override
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException {
return withExceptionHandling(() -> restTemplate.getForEntity(url, responseType));
}
#Override
public <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException {
return withExceptionHandling(() -> restTemplate.postForEntity(url, request, responseType));
}
private <T> ResponseEntity<T> withExceptionHandling(Supplier<ResponseEntity<T>> action) {
try {
return action.get();
} catch (HttpClientErrorException ex) {
return new ResponseEntity<>(ex.getStatusCode());
}
}
}
Recently had a usecase for this. My solution:
public class MyErrorHandler implements ResponseErrorHandler {
#Override
public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
return hasError(clientHttpResponse.getStatusCode());
}
#Override
public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
HttpStatus statusCode = clientHttpResponse.getStatusCode();
MediaType contentType = clientHttpResponse
.getHeaders()
.getContentType();
Charset charset = contentType != null ? contentType.getCharset() : null;
byte[] body = FileCopyUtils.copyToByteArray(clientHttpResponse.getBody());
switch (statusCode.series()) {
case CLIENT_ERROR:
throw new HttpClientErrorException(statusCode, clientHttpResponse.getStatusText(), body, charset);
case SERVER_ERROR:
throw new HttpServerErrorException(statusCode, clientHttpResponse.getStatusText(), body, charset);
default:
throw new RestClientException("Unknown status code [" + statusCode + "]");
}
}
private boolean hasError(HttpStatus statusCode) {
return (statusCode.series() == HttpStatus.Series.CLIENT_ERROR ||
statusCode.series() == HttpStatus.Series.SERVER_ERROR);
}
There is no such class implementing ResponseErrorHandler in Spring framework, so I just declared a bean:
#Bean
public RestTemplate getRestTemplate() {
return new RestTemplateBuilder()
.errorHandler(new DefaultResponseErrorHandler() {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
//do nothing
}
})
.build();
}
The best way to make a RestTemplate to work with 4XX/5XX errors without throwing exceptions I found is to create your own service, which uses RestTemplate :
public ResponseEntity<?> makeCall(CallData callData) {
logger.debug("[makeCall][url] " + callData.getUrl());
logger.debug("[makeCall][httpMethod] " + callData.getHttpMethod());
logger.debug("[makeCall][httpEntity] " + callData.getHttpEntity());
logger.debug("[makeCall][class] " + callData.getClazz());
logger.debug("[makeCall][params] " + callData.getQueryParams());
ResponseEntity<?> result;
try {
result = restTemplate.exchange(callData.getUrl(), callData.getHttpMethod(), callData.getHttpEntity(),
callData.getClazz(), callData.getQueryParams());
} catch (RestClientResponseException e) {
result = new ResponseEntity<String>(e.getResponseBodyAsString(), e.getResponseHeaders(), e.getRawStatusCode());
}
return result;
}
And in case of exception, simply catch it and create your own ResponseEntity.
This will allow you to work with the ResponseEntity object as excepted.

Rollback transaction in a Spring #Controller and show exception message in view

I have a Spring MVC controller and when an exception occurs I would like to show the exception message in the view and rollback the open transactions. The view contains a form like this:
<form:form method="POST" modelAttribute="registrationForm">
<form:errors path="*" cssClass="error-message"/>
...
</form:form>
I would like to show the exception message in the view, using the <form:errors ... /> feature. This is my current quite horrible solution:
#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);
}
The problem I'm facing is that when the exception is thrown, the transaction is not rolled back.
Can anyone help?
Thank you.
Update: slightly changed the question for better understanding
Update: found a quite horrible solution to display the exception message in the view. Still facing the problem with the transaction that is not rolled back when the exception is thrown.
Update: I changed #Transactional to #Transactional(rollbackFor = Exception.class) in the MyExampleDao.createFoo(...) method and now everything is working perfectly. This solution is still ugly IMO, does anyone have a better solution?
Don't have transactions in your controllers. Put them in your service layer.
You can create an abstract controller class that implements exception handling like so (then each separate controller extends obviously) :
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
}
}
But DO NOT put transaction in your controllers, put them in Service layer classes.
No one suggested a better solution than my ugly one. Here is my solution that solved the problem I had:
#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);
}
The only way you have to manage transaction in a controller scope, open a session from the 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{}
}

Resources