六、SpringBoot拦截器

六、SpringBoot拦截器

1、HandlerInterceptor拦截器的使用
  • 编写一个类实现HandlerInterceptor接口

    /**
     * 实现一个拦截器:
     *  1.实现HandlerInterceptor接口,重写方法
     *  2.在config配置文件中配置该拦截器
     */
    public class LoginInterceptor implements HandlerInterceptor {
        /**
         * 在目标路径执行之前执行
         * 可以获取到request和response对象
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            HttpSession session = request.getSession();
            Object user = session.getAttribute("loginUser");
            if (user != null){//验证是否登录逻辑,若不为user不为null则通过
                return true;
            }
            //执行到此,说明没有登录,将没有登录的信息保存到request域中,转发到登录页面
            request.setAttribute("msg","请登录");
            request.getRequestDispatcher("/login").forward(request,response);
            return false;
        }
        /**
         * 在目标方法执行之后执行
         * 可以获取到request、response和modelAndView对象
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            
        }
        /**
         * 在视图渲染之后执行
         * 可以获取到request、response和exception对象
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
        }
    }
    
  • 在config中配置

    @Configuration//标注这是一个控制类
    public class WebConfig implements WebMvcConfigurer {
        //跟web相关的配置类实现WebMvcConfigurer接口实现接口即可
        /**
         * 添加一个拦截器
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new LoginInterceptor())
                    .addPathPatterns("/**")// 配置 /** 会拦截所有的请求,包括静态资源
                    .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**");//设置哪些请求是不会拦截的,/**表示所有请求
        }
    }
    
2、HandlerInterceptor拦截原理
  1. 根据当前请求,找到HandlerExcutionChain[可以处理请求的hanlder一级handler的所有 拦截器]
  2. 先来顺序执行所有拦截器的 preHandle() 方法
    • 如果当前拦截器的preHandle()方法返回true,则执行下一个拦截器的preHandle()方法
    • 如果当前拦截器的preHandle()方法返回false,直接倒序执行所有已经执行了的拦截器的aftercompletion()方法
  3. 如果任何一个拦截器返回false,直接跳出,不再执行目标方法
  4. 所有拦截器都返回true,执行目标方法
  5. 倒序执行所有拦截器的postHandle()方法
  6. 前面的步骤有任何异常都会直接倒序触发afterCompletion()方法
  7. 页面成功渲染以后,也会倒序触发afterCompletion()方法
3、拦截器的执行流程图

请添加图片描述

4、SpringBoot实现文件上传
  • form表单中的文件上传

    <form th:action="@{/upload}" method="POST">
        <div class="form-group">
            <label for="exampleInputFile">单个文件</label>
            <input type="file" name="singleImg" id="exampleInputFile">
        <!--type="file"没有multiple属性时表示只能上传单个文件-->
        <!--type="file"添加multiple属性时表示可以上传多个文件-->
        </div>
        <div class="form-group">
             <label for="exampleInputFile">多个文件</label>
             <input type="file" name="photos" multiple>
         </div>
    </form>
    
  • 后台中controller的编写

    @PostMapping("/upload")
        public String upload(
                 @RequestPart("singleImg") MultipartFile singleImg,
                 @RequestPart("photos") MultipartFile[] photos) throws IOException {
    
            log.info("singleImg={},photos={}",singleImg.getSize(),photos.length);
            if(!singleImg.isEmpty()){
                //保存到文件服务器,OSS服务器
                String originalFilename = singleImg.getOriginalFilename();
                headerImg.transferTo(new File("H:\\cache\\"+originalFilename));
            }
            if(photos.length > 0){
                for (MultipartFile photo : photos) {
                    if(!photo.isEmpty()){
                        String originalFilename = photo.getOriginalFilename();
                        photo.transferTo(new File("H:\\cache\\"+originalFilename));
                    }
                }
            }
            return "index";
        }
    
  • SpringBoot中文件上传时存在大小的限制,可以在application.properties配置文件中修改

    spring.servlet.multipart.max-file-size=10MB
    spring.servlet.multipart.max-request-size=100MB
    
5、文件上传实现原理
  • 自动配置好StandardServletMultipartResolver[文件上传解析器]
  • 原理步骤:
    1. 请求进来使用文件上传解析器判断(isMultipart)并封装(resolveMultipart)返回(MultipartHttpServletRequest)文件上传请求
    2. 参数解析器来解析请求中的文件内容封装成MultipartFile
    3. 将request中文件信息封装为一个Map: MultiValueMap<String,MultipartFile> FileCopyUtils实现文件流的拷贝
6、异常处理
  • 默认情况下,SpringBoot提供/error处理所有错误的映射
  • 对于机器客户端(如:postman),它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息,对于浏览器客户端,响应一个 "Whitelabel"错误视图,以html格式城乡吸纳同的数据
  • 要对其进行自定义,添加View解析为error
  • error目录下的4XX,5XX页面会被自动解析(4xx.html,5xx.html都会被解析)
  • 要完全替换默认行为,可以实现ErrorController,并注册该类型的Bean定义,或添加ErrorAttributes类型的组件,使用现有的机制替换其内容
7、异常处理自动配置原理
  1. ErrorMvcAutoConfiguration : 自动配置异常处理规则
    • 容器中的组件: 类型: DefaultErroributes -> id: errorAttributes
      • public class DefaultErrorAttributes implements ErrorAttributes HandlerExceptionResolver
      • DefaultErrorAttributes : 定义错误页面中可以包含哪些数据
    • 容器中的组件: 类型: BasicErrorController -> id: basicErrorController (json + 白页 适配响应)
      • 处理默认 /error路径的请求 : 页面响应 new ModelAndView(“error”,model);
      • 容器中有组件 View -> id是error; (响应默认错误页)
      • 容器中放组件 BeanNameViewResolver(驶入解析器) : 按照返回的视图名称作为组件的id去容器中寻找View对象
    • 容器中的组件 : 类型 : DefaultErrorViewResolver -> id : conventionErrorViewResolver
      • 如果发生错误,会以Http的状态码作为视图页地址(viewName),找到真正的页面
      • error/4xx、5xx.html
8、异常处理流程
  1. 执行目标方法,目标方法运行期间有任何异常都会被catch、而且标志当前请求结束,并且使用dispatchException

  2. 进入视图解析流程(页面渲染)

    processDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException)
    
  3. mv = processHandlerException : 处理handler发生的异常,处理完成后返回ModelAndView

    1. 遍历所有的handlerExceptionResolvers,看谁能处理当前异常[HandlerExceptionResolver(处理器异常解析器)]
    2. 系统默认的 异常解析器:
      1. DefaultErrorAttributes
      2. HandlerExceptionResolverComposite
        • ExceptionHandlerExceptionResolver
        • ResponseStatusExceptionResolver
        • DefaultHandlerExceptionResolver
    3. DefaultErrorAttributes先处理异常,把异常信息保存到request域中,并返回null
    4. 默认没有人处理任何异常,所有异常会被抛出
      1. 如果没有任何人能处理异常,最终底层就发发送/error请求,会被底层的BasicErrorController处理
      2. 解析错误视图: 遍历所有的ErrorViewResolver 看谁能解析
      3. 默认的DefaultErrorViewResolver,作用是把响应状态码作为错误页的地址,error/500.html
      4. 模板引擎最终响应这个页面 error/500.html
9、定制异常处理
  • 方式一:自定义错误页:

    • error/404.html(error/500.html) : 有精确的错误状态码就匹配精确,没有就找4XX.html页面,如果都没有则触发白页
  • 方式二 : @ControllerAdvice + @ExceptionHandler 处理全局异常 : 底层是 : ExceptionHandlerExceptionResovler支持完成的

    @ControllerAdvice
    public class AdviceHandlerException {
        @ExceptionHandler({ArithmeticException.class,NullPointerException.class})//可以处理那些异常
        public String handlerException(Exception e){
            /*
            异常处理的逻辑
             */
            return "login";//视图地址
        }
    }
    
  • 方式三 : @ResponseStatus + 自定义异常 : 底层是 ResponseStatusExceptionResolver , 把responsestatus注解的信息底层调用 response.sendError(statusCode,resolvedReason) : 由tomcat发送 /error

    • 自定义异常类 MyException.java

      @ResponseStatus(value = HttpStatus.FORBIDDEN,reason = "自定义的异常")
      public class MyException extends RuntimeException{//java中所有自定义的异常必须继承RuntimeException类
          public MyException(){}//提供空参构造器
          public MyException(String message){//调用父类的构造器
              super(message);
          }
      }
      
    • 可以用来处理手动抛出的异常

  • 方式四 : Spring底层的异常,如 参数类型转换异常 : DefaultHandlerExceptionResolver 处理框架底层异常

    • response.sendError(HttpServletResponse.SC_BAD_REQUEST,ex.getMessage())
  • 方式五 : 自定义类实现 HandlerExceptionResolver 处理异常 : 可以作为默认的全部异常处理规则

  • 方式六 : ErrorViewResolver : 实现自定义处理异常

    • response.sendError error请求就会转给controller
    • 你的异常没有任何人能处理 tomcat底层response.sendError error请求会转给 controller
    • basicErrorController 要去的页面地址是 ErrorViewResolver
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值