TODO: An neuen Fehler anpassen, Separates Fehler-Template weg? Mehr...?
authorKai Moritz <kai@juplo.de>
Sat, 19 Sep 2020 10:46:52 +0000 (12:46 +0200)
committerKai Moritz <kai@juplo.de>
Mon, 28 Sep 2020 19:25:45 +0000 (21:25 +0200)
Added a working @ExceptionHandler

* Both handlers resolve the handled exception as 503 Internal Server Error
  and are using the template "error/503", which was extended to print a
  message, that the reported exception was catched and handled.
* If one starts the app, it is clearly visible, that the mechanism only
  works for exceptions, that are thrown in the context of the controller.
* Also added a test-case, that shows, that MockMvc shows the expected
  behaviour for exceptions, that are thrown inside the container.

src/main/java/de/juplo/demo/ExampleController.java
src/main/java/de/juplo/demo/ExampleService.java
src/main/resources/templates/resolved.html [new file with mode: 0644]
src/test/java/de/juplo/demo/ExceptionHandlingApplicationTests.java

index e16b147..f18f892 100644 (file)
@@ -5,10 +5,9 @@ import org.slf4j.LoggerFactory;
 import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.ModelAndView;
 import org.thymeleaf.exceptions.TemplateInputException;
 
 import java.util.Optional;
@@ -43,11 +42,40 @@ public class ExampleController
         return "view";
     }
 
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    @ExceptionHandler(IllegalArgumentException.class)
+    public ModelAndView illegalArgumentException(IllegalArgumentException e)
+    {
+        LOG.error("{}: {}", HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage());
+        ModelAndView mav = new ModelAndView("resolved");
+        mav.addObject("exception", e);
+        return mav;
+    }
+
+    /**
+     * This {@link ExceptionHandler @ExceptionHander} is never triggered,
+     * because the exception is not thrown inside the controller:
+     * <strong>It is functionless!</strong>
+     * <p>
+     *     The exception is thrown by Thymeleaf, which is called by the
+     *     {@link DispatcherServlet} after the controller has finished its
+     *     work during the rendering of the outcome.
+     * </p>
+     * <p>
+     *     {@link ExceptionHandler @ExceptionHander's} are not able, to catch
+     *     and resolve exceptions, which are thrown outside of the scope of the
+     *     controller.
+     *     This is also true for {@link ControllerAdvice}.
+     * </p>
+     */
     @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
     @ExceptionHandler(TemplateInputException.class)
-    public void templateInputException(TemplateInputException e)
+    public ModelAndView templateInputException(TemplateInputException e)
     {
         LOG.error("{}: {}", HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage());
+        ModelAndView mav = new ModelAndView("resolved");
+        mav.addObject("exception", e);
+        return mav;
     }
 }
 
index ec21629..45f2ca1 100644 (file)
@@ -13,8 +13,14 @@ public class ExampleService
             return Optional.empty();
 
         if (answer == 42)
+        {
             return Optional.of(true);
+        }
         else
+        {
+            if (answer % 7 == 0)
+                throw new IllegalArgumentException(answer + " is devidable by 7!");
             return Optional.of(false);
+        }
     }
 }
diff --git a/src/main/resources/templates/resolved.html b/src/main/resources/templates/resolved.html
new file mode 100644 (file)
index 0000000..32f64f8
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html xmlns:th="http://www.thymeleaf.org">
+  <head>
+    <title th:text="'503: ' + ${exception.getClass().getSimpleName()}">Testing Exception-Handling - Template for 503</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  </head>
+  <body>
+    <h1 th:text="'503: ' + ${exception.getClass().getSimpleName()}">Template for 503</h1>
+    <div>
+      <p><strong th:text="'Catched exception: ' + ${exception}">EXCEPTION</strong></p>
+      <p><a href="#" th:href="@{/}">Back to HOME</a></p>
+    </div>
+  </body>
+</html>
index b7891e4..b450f17 100644 (file)
@@ -86,4 +86,11 @@ class ExceptionHandlingApplicationTests {
                                .perform(get(URI.create("http://FOO/?answer=bar")))
                                .andExpect(status().isBadRequest());
        }
+
+       @Test
+       void test503() throws Exception {
+               mvc
+                               .perform(get(URI.create("http://FOO/?template=boom")))
+                               .andExpect(status().isInternalServerError());
+       }
 }