Handling Exceptions in Web UI

Table of Contents

The Issue

There is nothing worse than presenting a Java Stacktrace in a WebUI, full of technical Details about your Server environment of the Web App itself:

So how can we avoid this? You don't want to share this informations with the users, it would scare them and they wouldn't understand it.

What is happing here, is that the Page will try to redirect to the /error Page. This Page does not exist as real HTML Page. This is just a generated default page out of the box. This is generated in code. But we can create our own error page to avoid this.

Custom Error Page

Let's create a new HTML Page under resources/templates/error.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Error Page</title>
</head>
<body>
Something went horribly, terribly wrong. Please try again.
</body>
</html>

To use this Page, because it's under the templates folder it needs a controller in order to work.

Error Controller

So we need to create an error Controller for this. Let's create a new Java Class called ErrorController.java with this content:

package ch.finecloud.peopledbweb.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("error")
public class ErrorController {

    @GetMapping
    public String getErrorPage() {
        return "error";
    }
}

If a User now again hits an error, this will be shown:

Much better, isn't it? But we can do even better. If we know what kind of error could be thrown, we can provide a more accurate error page. In our current case we need to add a specific try catch block in the save method, which can catch StorageExceptions:

    @PostMapping
    public String savePerson(Model model, @Valid Person person, Errors errors, @RequestParam("photoFilename") MultipartFile photoFile) throws IOException {
        log.info(person);
        log.info("Filename: " + photoFile.getOriginalFilename());
        log.info("File size: " + photoFile.getSize());
        log.info("Errors: " + errors);
        if (!errors.hasErrors()) {
            try {
                fileStorageRepository.save(photoFile.getOriginalFilename(), photoFile.getInputStream());
                personRepository.save(person);
                return "redirect:people";
            } catch (StorageException e) {
                model.addAttribute("errorMsg", "System is currently unable to accept photo files at this time.");
                return "people";
            }
        }
        return "people";
    }

Now let's add this custom error Message to the people.html page like so:

<div class="alert alert-danger" role="alert" th:text="${errorMsg}" th:if="${errorMsg}">
    A simple danger alert-check it out!
</div>

The final result looks like this:

The User will be redirected back to the people page with the provided values. The Error Message will be displayed in the middle of the page.