add: Exception Error响应的例子
diff --git a/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/controller/FooController.java b/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/controller/FooController.java
index 120cb3c..c69a8aa 100644
--- a/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/controller/FooController.java
+++ b/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/controller/FooController.java
@@ -1,12 +1,14 @@
 package com.supwisdom.leaveschool.foo.controller;
 
+import com.supwisdom.infras.lang.random.RandomGenerator;
+import com.supwisdom.leaveschool.foo.model.BarException;
 import com.supwisdom.leaveschool.foo.model.Foo;
+import com.supwisdom.leaveschool.foo.model.FooException;
+import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.server.ResponseStatusException;
 
 import javax.validation.Valid;
 
@@ -15,7 +17,7 @@
 public class FooController {
 
   /**
-   * http://localhost:8080/foo/greeting/abc
+   * curl -i -s -X GET -H 'Accept:text/html' http://localhost:8080/foo/greeting/abc
    *
    * @param name
    * @param model
@@ -29,17 +31,48 @@
 
   /**
    * good请求:
-   * http://localhost:8080/foo/model?name=abc&age=10
+   * curl -i -s -X POST -H 'Accept:text/html' 'http://localhost:8080/foo/model?name=abc&age=1'
    *
    * bad请求:
-   * http://localhost:8080/foo/model?name=abc&age=-1
+   * curl -i -s -X POST -H 'Accept:text/html' 'http://localhost:8080/foo/model?name=abc&age=-1'
    *
    * @param foo
    * @return
    */
-  @GetMapping(path = "/model")
+  @PostMapping(path = "/model")
   public String model(@Valid @ModelAttribute Foo foo) {
     return "foo/model";
   }
 
+  /**
+   * curl -i -s -X GET -H 'Accept:text/html' 'http://localhost:8080/foo/foo-exception?with-message=1'
+   * curl -i -s -X GET -H 'Accept:text/html' 'http://localhost:8080/foo/foo-exception?with-message=0'
+   *
+   * @return
+   * @throws FooException
+   */
+  @GetMapping(path = "/foo-exception")
+  public String exception1(@RequestParam(value = "with-message", required = false, defaultValue = "false") boolean withMessage) throws FooException {
+    if (withMessage) {
+      throw new FooException(RandomGenerator.randomStringAlphabetic(10));
+    } else {
+      throw new FooException();
+    }
+
+  }
+
+  /**
+   * curl -i -s -X GET -H 'Accept:text/html' 'http://localhost:8080/foo/bar-exception'
+   *
+   * @return
+   */
+  @GetMapping(path = "/bar-exception")
+  public String exception2() {
+    try {
+      throw new BarException();
+    } catch (BarException e) {
+      throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Customized Bar Error Reason", e);
+    }
+  }
+
 }
diff --git a/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/controller/FooRestController.java b/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/controller/FooRestController.java
index d8d1f98..b5b8911 100644
--- a/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/controller/FooRestController.java
+++ b/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/controller/FooRestController.java
@@ -1,13 +1,13 @@
 package com.supwisdom.leaveschool.foo.controller;
 
+import com.supwisdom.infras.lang.random.RandomGenerator;
 import com.supwisdom.leaveschool.foo.model.BarException;
 import com.supwisdom.leaveschool.foo.model.Foo;
 import com.supwisdom.leaveschool.foo.model.FooException;
+import org.springframework.http.HttpStatus;
 import org.springframework.util.MimeTypeUtils;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.server.ResponseStatusException;
 
 import javax.validation.Valid;
 import java.util.HashMap;
@@ -21,7 +21,7 @@
 public class FooRestController {
 
   /**
-   * curl -H 'Accept:application/json' 'http://localhost:8080/foo-rest/greeting/abc'
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://localhost:8080/foo-rest/greeting/abc'
    *
    * @param name
    * @return
@@ -35,26 +35,48 @@
 
   /**
    * good请求:
-   * curl -H 'Accept=application/json' 'http://localhost:8080/foo-rest/greeting?name=abc&age=1
+   * curl -i -s -X POST -H 'Accept=application/json' 'http://localhost:8080/foo-rest/model?name=abc&age=1'
+   *
    * bad请求:
-   * curl -H 'Accept=application/json' 'http://localhost:8080/foo-rest/greeting?name=abc&age=-1
+   * curl -i -s -X POST -H 'Accept=application/json' 'http://localhost:8080/foo-rest/model?name=abc&age=-1'
    *
    * @param foo
    * @return
    */
-  @GetMapping(path = "/model", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @PostMapping(path = "/model", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
   public Foo model(@Valid Foo foo) {
     return foo;
   }
 
-  @GetMapping(path = "/exception1", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
-  public Map<String, Object> exception1() {
-    throw new FooException();
+  /**
+   * curl -i -s -X GET -H 'Accept=application/json' 'http://localhost:8080/foo-rest/foo-exception?with-message=1'
+   * curl -i -s -X GET -H 'Accept=application/json' 'http://localhost:8080/foo-rest/foo-exception?with-message=0'
+   *
+   * @return
+   * @throws FooException
+   */
+  @GetMapping(path = "/foo-exception", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  public Map<String, Object> exception1(@RequestParam(value = "with-message", required = false, defaultValue = "false") boolean withMessage) throws FooException {
+    if (withMessage) {
+      throw new FooException(RandomGenerator.randomStringAlphabetic(10));
+    } else {
+      throw new FooException();
+    }
+
   }
 
-  @GetMapping(path = "/exception2", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  /**
+   * curl -i -s -X GET -H 'Accept=application/json' 'http://localhost:8080/foo-rest/bar-exception'
+   *
+   * @return
+   */
+  @GetMapping(path = "/bar-exception", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
   public Map<String, Object> exception2() {
-    throw new BarException();
+    try {
+      throw new BarException();
+    } catch (BarException e) {
+      throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Customized Bar Error Reason", e);
+    }
   }
 
 }
diff --git a/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/model/BarException.java b/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/model/BarException.java
index b0bb8b7..e5b18a1 100644
--- a/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/model/BarException.java
+++ b/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/model/BarException.java
@@ -1,6 +1,6 @@
 package com.supwisdom.leaveschool.foo.model;
 
-public class BarException extends RuntimeException {
+public class BarException extends Exception {
   public BarException() {
   }
 
diff --git a/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/model/FooException.java b/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/model/FooException.java
index 0542d65..1b319af 100644
--- a/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/model/FooException.java
+++ b/samples/foo/src/main/java/com/supwisdom/leaveschool/foo/model/FooException.java
@@ -3,6 +3,18 @@
 import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.ResponseStatus;
 
-@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "Foo Reason")
-public class FooException extends RuntimeException {
+
+@ResponseStatus(
+    code = HttpStatus.BAD_REQUEST,
+    /**
+     * 这里写了reason,那么错误消息里的message就只会是这个值
+     */
+    reason = "Customized Foo Error Reason")
+public class FooException extends Exception {
+  public FooException() {
+  }
+
+  public FooException(String message) {
+    super(message);
+  }
 }
diff --git a/samples/foo/src/main/resources/application.yaml b/samples/foo/src/main/resources/application.yaml
index 4943342..2dfd7aa 100644
--- a/samples/foo/src/main/resources/application.yaml
+++ b/samples/foo/src/main/resources/application.yaml
@@ -5,5 +5,16 @@
 infras:
   mvc:
     custom-error:
+      enabled: true
       error-map:
-        com.supwisdom.leaveschool.foo.model.BarException: Bar Reason
+        org.springframework.validation.BindException: Customized Bind Error Reason
+      include-message: true
+      include-errors: true
+      include-error: true
+      include-exception: true
+      include-path: true
+      include-timestamp: true
+      include-status: true
+logging:
+  level:
+    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod: trace
diff --git a/samples/foo/src/main/resources/templates/error.html b/samples/foo/src/main/resources/templates/error.html
new file mode 100644
index 0000000..a136738
--- /dev/null
+++ b/samples/foo/src/main/resources/templates/error.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html xmlns:th="http://www.thymeleaf.org">
+<head>
+  <title>Customized Error Page</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+<body>
+<p>Error: <span th:text="${error}"></span></p>
+<p>Status: <span th:text="${status}"></span></p>
+<p>Message: <span th:text="${message}"></span></p>
+<p>Errors: <span th:text="${errors}"></span></p>
+<p>Exception: <span th:text="${exception}"></span></p>
+<p>Timestamp: <span th:text="${timestamp}"></span></p>
+<p>Path: <span th:text="${path}"></span></p>
+</body>
+</html>