一.拦截器
1.使用
- 访问任何请求,都只有登录才能访问,挨个写入请求太困难,使用拦截器机制handlerIntercepter(prehandle方法,posthandle方法,afterCompletion方法)
- 编写一个拦截器实现handlerInterceptor接口
- 编写的拦截器注册到容器中(实现webMvcConfigure的addInterceptors方法)
- 指定拦截规则(如果是拦截所有,静态资源也会被拦截)
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")//所有请求,包括静态资源也会拦截
.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**");//放行的请求
2.拦截器原理
- 根据当前请求找到一个具体的handler执行,并且找到handler的所有拦截器,即handlerExecution
- 找到了handler适配器后
- 执行目标方法之前执行了 所有handler的prehandle方法
- 对所有的拦截器执行for循环顺序执行所有拦截器调用prehandle方法
- 如果当前拦截器prehandle返回true,放行,执行下一个拦截器的prehandle
- 如果当前拦截器返回为false,直接倒序执行所有已经执行了的拦截器的afterCompletion
- 如果任何一个拦截器执行失败返回false,直接跳出不执行目标方法
- (所有拦截器都返回true)执行目标方法
- 执行目标方法后执行所有的倒序posthandler方法
- 前边步骤有任何异常,都直接触发拦截器aftercompletion方法
- 页面渲染逻辑中
- 页面成功渲染完成之后
- 倒序触发所有拦截器的aftercompletion

二.文件上传
1.文件上传使用
@PostMapping("/upload")
public String upload(@RequestParam("email") String email,
@RequestParam("username") String username,
@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos) throws IOException {
if(!headerImg.isEmpty()){
//保存到磁盘上
String originalFilename = headerImg.getOriginalFilename();
headerImg.transferTo(new File("E:\\"+originalFilename));
}
if(photos.length>0){
for(MultipartFile photo:photos){
if(!photo.isEmpty()){
String originalFilename = photo.getOriginalFilename();
photo.transferTo(new File("E:\\"+originalFilename));
}
}
}
return "main";
}
2.文件上传源码解析
- 自动配置好了standardServletMultipartResolver(文件上传解析器)
- 请求进来使用文件上传解析器判断并封装上传请求
- 判断请求是否为文件上传请求(判断表单的内容类型是否为multipart/)
- 判断是文件上传请求并封装
- 将request封装为multipartHttpServletRequest
- 找到handler来处理请求,执行具体的handler来执行
- 利用参数解析器解析文件上传(@RequestPart(“headerImg”) MultipartFile headerImg,)
- 找到参数解析器RequestPartMethod来将请求中的文件内容封装为MultipartFile
三.异常处理
1.springboot处理错误
- 默认情况下,springboot提供/error处理所有错误的映射
- 对于机器客户端,产生json
- 对于浏览器客户端,产生错误页
都有 时间戳,都有状态码
2.自定义错误页面
3.错误处理(自动配置)原理
①容器中配置
- 有配置类errorMVCAutoConfiguration 自动配置异常处理规则
- 给容器中放置了 DefaultErrorAttribute类型的组件 id:errorAttributes,定义错误页面可以包含的信息
- 给容器中放置了 BasicErrorController类型的组件 id:basicErrorController(处理默认/error路径的请求;页面响应一个modelAndView(error))
- 容器中有View组件,id:error(容器中有一个视图解析器(响应默认错误页)BeanNameViewResolver,按照返回的视图名error作为组件的id去找view对象)
- 容器中中放置了DefaultErrorViewResolver,id=…,如果发生错误,会以HTTP状态码作为视图页地址(404,5xx)找到真正的页面 error/404,5xx.html
- 如果想要返回页面,就会找error视图(staticView)。(默认是一个白页)
- 上面的controller组件中的两个方法(responseEntity写出去json数据,errorHtml写出去一个视图 适配响应)
②整体流程(异常处理)
- 找到适配器执行目标方法时(目标方法运行期间,有任何异常都会被catch,而且标志当前请求结束,并且用dispacthException进行封装)
- 进入视图解析流程(页面渲染?)传参
(request,response,handler,mv,dispatchException) - 处理handler异常最后返回一个mv
- 遍历handlerExceptionResolvers处理器异常解析器看谁能处理当前异常
- DefaultErrorAttribute…给请求域中保存了异常信息并且返回空(必须返回不为空才结束)
- (继续解析) 三个异常解析器的组合(第一个异常解析器不满足其要求,第二个异常解析器不满足其要求,第三个异常解析器不满足要求)
- 默认没有任何解析器能处理异常,异常被抛出
- 如果没有任何解析器处理异常,最终底层会发送(转发)/error请求
- 接下来 BasicErrorController来处理/error请求
- 此时是浏览器发送,此时其中方法处理/error
- 此时会解析错误视图,遍历所有的ErrorViewResolver错误视图解析器看谁能处理错误视图
- DefaultErrorViewResolver把响应的状态码500拿到作为错误页的地址拼接/error/500,然后通过模板引擎判断有没有/error/500页面,如果有直接返回页面带.html页面
4.定制错误处理逻辑
- 自定义错误页 放在error下的4xx 和5xx(400错误无法解决)精确匹配
- 利用@ControllerAdvice + @ExceptionHandler处理异常
- @ControllerAdvice该类为处理异常类 @ExceptionHandler({ArithmeticException.class,NullPointerException.class})为该方法能处理的异常类型
- 原理?
- 在三个异常解析器的组合中第一个异常解析器ExceptionHandlerExceptionResolver能够处理(第一个异常处理器判断是否有标志@ExceptionHandler的方法,如果有标志,就调用该方法进行处理)
- return 字符串(放到了modelAndView) 等于正常的方法
- 抛出自己定义的异常
@ResponseStatus()可以在自定义异常类声明一个错误状态码(也可以被解析)
- 原理?
- 在三个异常解析器的组合中第二个异常解析器ResponseStatusExceptionResolver能够处理(第二个异常处理器判断当前异常是否有@ResponseStatus注解,如果有,就调用该方法进行处理)
- 将注解的状态码解析出来,然后直接跳去错误页 response.sendError();tomcat发送的/error,然后进入处理error逻辑
- 底层异常(参数不存在)框架抛出异常
- 在三个异常解析器的组合中第三个异常解析器DefaultHandlerExceptionResolver能够处理(第三个异常处理器判断当前异常是否是springmvc底层的异常,如果是,就调用该方法进行处理)
- 然后sendError(执行方法立即结束,tomcat抛出一个/Error(包含状态码),看谁能处理)
- 正常直接返回tomcat的错误页,但是sprignmvc底层有servlet专门处理/error请求
5.自定义异常解析器
- 直接定义返回值modelandView不让其他异常解析器解析,并且response.sendError(511,“错误”) 即tomcat发送 /error
- @order 让其排在第一位
- @component成为bean
- 实现handlerExceptionResolver异常解析器
6.ErrorViewResolver实现自定义处理异常
- response.sendError error请求就回转给controller
- 异常没人处理,也会直接senderror(modelandview都是null)
- 要去的页面地址是ErrorViewResolver解析的,去/error/xxx.html页面