Alex Man
Alex Man

Reputation: 4886

Spring MVC - Displaying Exception in View (JSP Page)

I have created an application in Spring MVC for testing the rollback and commit functionality. I am using Transaction using. Here in the service i have created another contact objects without specifying employee id which is a required field. The application works fine when exception is comming while saving and rollback is working.

But the problem is the Exception is printing in my jsp page.

Can anyone please tell me some solution for preventing displaying he exception in te view

Controller

@RequestMapping(value="/saveContact", method=RequestMethod.POST)
public String create(@ModelAttribute("newContact")Contacts contact, BindingResult result, SessionStatus status)
{
    validator.validate(contact, result);
    if (result.hasErrors()) 
    {               
        return "newContact";
    }
    contactsDAO.save(contact);
    status.setComplete();
    return "redirect:viewAllContacts.do";
}

Service

public int save(Contacts contact)
{
    int i = 0;
    try
    {
        i = (Integer) sessionFactory.getCurrentSession().save(contact);
        Contacts contacts =new Contacts();
        contacts.setAddress("ABCD");
        contacts.setMobile("8181");
        i = (Integer) sessionFactory.getCurrentSession().save(contacts);
    }
    catch(Exception exception)
    {
        exception.printStackTrace();
    }
    return i;
}

EDIT

@RequestMapping(value="/saveContact", method=RequestMethod.POST)
public String create(@ModelAttribute("newContact")Contacts contact, BindingResult result, SessionStatus status) throws SQLException
{
    validator.validate(contact, result);
    if (result.hasErrors()) 
    {               
        return "newContact";
    }
    try {
        contactsDAO.save(contact); 
    }
    catch (Exception ex) {
        System.out.println("enrtered");
        result.reject("DUPKEY");
        ex.printStackTrace();
        return "redirect:saveContact.do";
    } 
    status.setComplete();
    return "redirect:viewAllContacts.do";
}

Upvotes: 2

Views: 8373

Answers (2)

Serge Ballesta
Serge Ballesta

Reputation: 148870

You should never let an exception thrown in service layer arrive directly in user browser. As suggested by Vinit Prajapati you can configure a HandlerExceptionResolver that will display appropriate views in case of an exception. You can also have a per controller exception handling mechanisme with one or more @ExceptionHandler annotated method(s) that will be fired in case of a configured exception and that can be used almost like @RequestMapping annotated methods. At a last ressort you can have explicit try-catch blocks in controller methods.

Extracts from Spring Framework Reference Manual : You use the @ExceptionHandler method annotation within a controller to specify which method is invoked when an exception of a specific type is thrown during the execution of controller methods ... The @ExceptionHandler value can be set to an array of Exception types. If an exception is thrown matches one of the types in the list, then the method annotated with the matching @ExceptionHandler will be invoked ... Much like standard controller methods annotated with a @RequestMapping annotation, the method arguments and return values of @ExceptionHandler methods are very flexible... The return type can be a String, which is interpreted as a view name or a ModelAndView object.

In my own code, I use @ExceptionHandler for general errors such as unaccessible database, but use try-catch blocs in controller if I want to deal with exceptions really caused by business rules and for which I prefere to use <form:errors> tags in the view, explicitely calling Errors.reject() in controller.

EDIT: concrete examples

Suppose you want to display special view in case of DataIntegrityViolationException

In controller

@ExceptionHandler(value = {DataIntegrityViolationException.class})
public ModelAndViewexceptionHandler(Exception ex, Locale locale) {
    String msg = ex.getMessage();
    // or if you have a I18n app : String msg = messageSource.getMessage("DUPKEY", null, locale);
    return new ModelAndView("duplicate", "msg", msg);
}

with "duplicate"leading to a jsp where ${msg} will display the exception message. Of course for that to work, your service must throw a DataIntegrityViolationException ...

If you prefere the error to be displayed in normal view, you can do instead

@RequestMapping(value="/saveContact", method=RequestMethod.POST)
public String create(@ModelAttribute("newContact")Contacts contact, BindingResult result, SessionStatus status)
{
    validator.validate(contact, result);
    if (result.hasErrors()) 
    {               
        return "newContact";
    }
    try {
        contactsDAO.save(contact);
    }
    catch (DataIntegrityViolationException ex) {
        result.reject("DUPKEY");
        return "newContact";
    }
    status.setComplete();
    return "redirect:viewAllContacts.do";
}

With that last construct you will display the error message corresponding to DUPKEY in your configured MessageSourcebean like other global errors in your jsp view through the tag <form:errors/> with no path in it.

<form:form>
      <%-- Show global errors (notably DUPKEY) --%>
      <form:errors/>
      <table>
          <tr>
              <td>Address:</td>
              <td><form:input path="address" /></td>
              <%-- Show errors for address field --%>
              <td><form:errors path="address" /></td>
          </tr>
...
</form:form>

Upvotes: 4

NimChimpsky
NimChimpsky

Reputation: 47280

Create a base controller class (which your others extend), and for example try this method (although you'll want to handle different errors with different methods, but this will get you started):

    /*
 * Default exception handler, catches 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
    logger.error(strStackTrace); // send to logger first
    emailService.sendAlertMail(strStackTrace);
    return "exception"; // default friendly exception message for user
}

Upvotes: 4

Related Questions