• (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;
        }
    
  • 相关阅读:
    mysql命令行如何得到表结构
    liunx cron问题
    关于SQL判断某个值的查询
    给自己的nexus私人仓库添加缺少的jar包
    MyEclipse9 Maven开发Web工程 详细配置
    springMVC 之 Controller
    java 动态代理
    Freemarker
    java编程陷阱
    HttpClient应用
  • 原文地址:https://www.cnblogs.com/young-youth/p/11665579.html
Copyright © 2020-2023  润新知