(6)Spring Boot web开发 --- 错误处理页面


处理时间(Date)类型

Spring Boot 进行参数绑定使用的是 SpringMvc ,涉及 Date 类型的参数绑定的时候,默认是时间格式是 yyyy/MM/dd ,我们可以自定义格式,只需要配置文件里面配置下:

# 日期格式
spring.mvc.date-format=yyyy.MM.dd

thymeleaf 页面拼接字符串

表达式之间直接使用 + 拼接,比如 :@{/emp/} + ${emp.id} ;


映射路径占位符

在映射路径中可以使用占位符的 @GetMapping(/emp/{id}) ;这样参数传入 id 就会被放到


使用 put、delete 方法

表单 仅支持两种方法提交,POST ,GET

如果想要使用其他方法,则需要进行一番操作;

  1. SpringMvc 配置 HiddenHttpMethodFilterSpring Boot 已经自动配置好了,美滋滋);

  2. 页面创建一个表单

  3. 创建一个 input 项,typehidden·name 属性值必须为 _method,然后 value 属性的值,就写我们想要使用的方法:

    <input type="hidden" name="_method" value="put">


错误处理机制

  1. Spring Boot 默认返回一个白板页面;

  2. 自定义错误响应

    • 定制错误的页面

      • 有模板引擎

        将错误页面放在 类路径templates/error 文件夹下面,命名为 状态码.html ,这样发生错误的时候,就会去寻找状态码对应的页面;

        当然这样很傻,那么多状态码,需要写很多页面,因此,还可以直接创建 4xx.html5xx.html ,这样发生 404,402,403 这些 4xx 的错误的时候,由于没有对应的页面,就会退而其次,匹配 4xx.html 页面,5xx 也是同样的道理 ;

        如果 4xx.html404.html 同时存在,这时候发生 404 错误,会匹配上 404.html ,精确优先 ;

        在页面中还可以获取一些信息:timestamp(时间戳)、status(状态码)、error(错误提示)、exception(异常对象),message(异常消息),errors(JSR303数据校验的错误信息)

      • 没有模板引擎

        没有模板引擎,就去静态资源文件夹下面,寻找对应的 4xx.html ,5xx.html

      • 以上两种情况都没有

        那就莫得选择了,只能使用 Spring Boot 的默认错误提示页面 ;

    • 定制错误 JSON

      自定义异常处理器,使用 @ControllerAdvice 标注类,然后在方法上,使用 @ExceptionHandler 标注要处理什么异常,然后只要发生了对应的异常,该方法就会得到调用,方法参数可以写一些我们自己想要获得的对象;

      @ControllerAdvice
      public class MyExceptionController {
      
          @ResponseBody
          @ExceptionHandler({UserNotExistException.class})
          public Map<String,Object> handlerUserNotExist(Exception e){
              Map<String,Object> map = new HashMap<>();
              map.put("code","Test Exception");
              map.put("message",e.getMessage());
              return map ;
          }
      }
      
      

      方法的返回值,就会被送到页面,但是这样有个缺点,丢失自适应效果(本来浏览器和终端方法,Spring Boot 会显示不同的效果的,浏览器显示 白板错误页面,终端显示 JSON ),无论是浏览器还是终端,都显示 JSON 串;

      进行改动下,转发到 /error炸,就可以自适应了:

       @ExceptionHandler({UserNotExistException.class})
          public String handlerUserNotExistAdaptive(Exception e){
              Map<String,Object> map = new HashMap<>();
              map.put("code","Test Exception");
              map.put("message",e.getMessage());
              // 转发到 /error
              return "forward:/error" ;
          }
      

      但是 又有新问题了:发生异常以后,状态码,就会变成 4xx ,5xx,然后被我上面的方法捕捉到以后,来了一个转发,异常被吞咽了,异常链断掉了,状态码已经变了,变为正常的 200,因为转发又没发生异常;

      虽然转发到 /error ,但是状态码已经变了,此时去 /error 下面,没有对应的页面了,就只能找默认的页面了;

      因此,我们在转发之前,设置下状态码:request.setAttribute("javax.servlet.error.status_code",400);,键不是瞎写的,是必须是这个:

      @ExceptionHandler({UserNotExistException.class})
          public String handlerUserNotExistAdaptive(Exception e, HttpServletRequest request){
              request.setAttribute("javax.servlet.error.status_code",400);
              Map<String,Object> map = new HashMap<>();
              map.put("code","Test Exception");
              map.put("message",e.getMessage());
              // 转发到 /error
              return "forward:/error" ;
          }
      

      现在还有最后一个问题,我们在转发的时候,带过去的数据,页面其实拿不到的,现在要解决这个问题:

      页面上能用的数据,或者 JSON 返回能用的数据,其实都是在 ErrorAttributes.class 类里面的,通过 getErrorAttibutes 获取的,因此,我们只需要获取到 getErrorAttibutes 方法的返回值,然后再返回值里面添加上我们自己的数据即可 ;

      @Component
      public class MyErrorAttributes extends DefaultErrorAttributes {
      
          @Override
          public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
              Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
              errorAttributes.put("message","Test");
              return errorAttributes;
          }
      }
      
      

如果我们在别的地方也有数据想要带到页面,需要向下面这样做:

  1. 首先在转发之前,将我们的数据放到域里面;

    
        @ExceptionHandler({UserNotExistException.class})
        public String handlerUserNotExistAdaptive(Exception e, HttpServletRequest request){
            request.setAttribute("javax.servlet.error.status_code",400);
    
            Map<String, Object> myErrorAttributesMap = new HashMap<>();
            myErrorAttributesMap.put("message","sasasa");
            myErrorAttributesMap.put("code","Test Exception");
            request.setAttribute("errorAttributesMap",myErrorAttributesMap);
    
            // 转发到 /error
            return "forward:/error" ;
        }
    
  2. 然后在 getErrorAttibutes 方法,从域里面取出来,然后添加到 getErrorAttibutes 方法的返回值中;

@Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
    // 数字代表域,0 是 request , 1 是 session ,
        Map<String, Object> errorAttributesMap = (Map<String, Object>) webRequest.getAttribute("errorAttributesMap", 0);
        Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
        errorAttributes.put("message","Test");
        errorAttributes.put("error",errorAttributesMap);
        return errorAttributes;
    }
posted @ 2019-03-06 13:58  Yiaz  阅读(106)  评论(0编辑  收藏  举报