Loading

Spring文档Snippets

InternalResourceViewResovler需要放在视图解析器链的最后

原文链接

你可以通过定义多于一个的解析器Bean来形成ViewResolver链,并且如果有必要的话,设置order属性来指定它们的顺序。记住,order属性越高,视图解析器在链中的位置就越靠后。

ViewResolver的约定中定义了它可以通过返回null来指示没有找到对应的View。然而,在JSP和InternalResourceViewResovler中,我们只能通过让RequestDispatcher来实际执行一次分派这一种办法来了解一个JSP是否存在。因此,你必须始终将InternalResourceViewResovler配置在所有视图解析器之后。

解析:上面所要阐述的就是,由于种种限制,InternalResourceViewResolver必须尝试解析任何的视图名,而不管底层的文件是否存在,所以他永远都不会返回null。如果你将它放到视图处理器链的前面,其它视图处理器将没有机会执行。

你可以利用的两个MultipartResovler

原文链接

org.springframework.web.multipart包下的MultipartResolver口是解析包含文件上传的multipart请求的策略接口。有两个具体的策略实现,一个实现基于Apache的Commons FileUpload,另一个基于Servlet3.0中(自带)的multipart请求解析。

解析:SpringMVC利用策略模式来实现文件上传,它定义了策略接口MultipartResovler,而我们目前有两个实现可以利用,分别是Apache的和Servlet3中自带的。使用Apache的需要导包并定义CommonsMultipartResolver,使用Servlet3的需要保证Servlet版本大于等于3,设置DispatcherServletMultipartConfig,并且定义StandardServletMultipartResolver

Controller默认参数解析逻辑

原文链接

如果一个方法参数没有匹配在这个表格中的前面的任何值,并且它是一个简单类型,那么它被@RequestParam注解来解析,否则,它被@ModelAttribute注解解析。

解析:在Controller方法中可以接收一些特殊参数,比如HttpServletRequestHttpEntity,详情在官方文档中的一个表格里。但如果一个参数不是表格里定义的,如果它是一个简单类型(BeanUtils.isSimpleProperty),那它会按照@RequestParam的逻辑来解析,否则它会按照@ModelAttribute的逻辑来解析。也就是说,这两个注解可以省略。

有些Model值不想被加到重定向URL中

原文链接

默认情况下,所有Model属性都被考虑作为重定向URL中的URI模板变量公开。在其余属性中,原始类型或原始类型的集合或数组将作为查询参数(重定向URL的querystring)自动追加。

在一个model实例是为了一个重定向而被特别准备时,将原始类型属性作为查询参数添加可能是我们所期望的。然而,在带注解的Controller中,模型可能包含被额外添加的用于渲染的属性。为了避免有这种属性被暴露在URL中的可能,一个被@RequestMapping标注的方法可以定义一个RedirectAttributes类型的参数,并且使用它来指定RedirectView的确切属性。如果方法执行了重定向,那么RedirectAttributes中的内容被使用,其它情况下,Model中的内容被使用。

解析:Model值如何被处理到View层,是具体的View实例决定的。在InternalResourceView中,Model值会被添加到request的属性中,而在RedirectView中,Model中的简单值会被拼接到URL的querystring上。但这有时并不是我们所预期的,为了避免这一问题,可以采用上面所说的办法。

@ExceptionHandler异常处理器对于Caused异常的处理

原文链接

异常可能与传播的顶级异常相匹配,或者是顶级异常的直接cause

root异常和cause异常匹配间的区别可能令你吃惊。

@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(IOException ex) {
    // ...
}

在上面的IOException的例子中,方法被调用时的实际参数类型通常是FileSystemException.classRemoteException.class,它们都是IOException的子类。然而,如果任意一个这种匹配的异常通过一个本身就是IOException的包装异常来传播,那么传入的异常示例就是包装异常(IOException)。

我们通常推荐你尽可能将这个参数签名中的类型定义的更加特化,以减少潜在的root与cause异常之间的匹配错误。

Spring MVC中对@ExceptionHandler方法的支持是建立在DispatcherServlet级别,HandlerExceptionResolver机制上的。

解析

这个用一个示例来解析,下面有一个和上面代码一样的方法:

@ExceptionHandler({FileSystemException.class, RemoteException.class})
public String handle(IOException e, Model model) {
    if (e.getCause() != null) {
        System.out.println("e is a wrapper exception and the actual exception is : " + e.getCause());
    } else {
        System.out.println("e is a root exception!");
    }
    model.addAttribute("exceptionName", e.getClass().getSimpleName());
    return "error";
}

下面我们编写三个会抛出异常的Controller方法进行测试

  1. 直接抛出IOException,但上面的方法只接收它的两个子类,所以没有走@ExceptionHandler

    @RequestMapping("/crashRootExceptionDirectly")
    public String crashRootExceptionDirectly() throws IOException {
        throw new IOException("ioexception");
    }
    

    img

  2. 直接抛出子类异常,毫无疑问,会正常的走@ExceptionHandler

    @RequestMapping("/crashSubExceptionDirectly")
    public String crashSubExceptionDirectly() throws FileSystemException {
        throw new FileSystemException("filesystem exception");
    }
    

    走到了@ExceptionHandler返回值中设置好的异常显示界面

    img

  3. 采用IOException包装子类异常,最终,@ExceptionHandler中接到的方法是父类异常

    @RequestMapping("/crashSubExceptionWrappedInRootException")
    public String crashSubExceptionWrappedInRootException() throws IOException {
        throw new IOException(new FileSystemException("filesystem exception"));
    }
    

    img

    但可以通过getCause来获取被包装的子异常

    img

  4. 采用毫不相干的异常包装FileSystemException,最终,@ExceptionHandler中接收到的是被包装异常

    @RequestMapping("/crashSubExceptionWrappedInRuntimeException")
    public String crashSubExceptionWrappedInRuntimeException() {
        throw new RuntimeException(new FileSystemException("filesystem exception"));
    }
    

    img

总结就是,在Controller方法发生异常时,SpringMVC(或者说它的HandlerAdapter)除了会考虑这个异常的直接类型之外,还会考虑它的cause的类型。一个例外就是当一个@ExceptionHandler方法由于cause类型匹配而被选中处理异常时,若它的方法参数就是包装异常的类型,那么被传入到异常对象是包装异常示例

SpringBoot自动配置

原文链接

SpringBoot的自动配置功能会基于你添加的Jar依赖来尝试自动的配置你的Spring应用。举例来说,如果HSQLDB在你的classpath下,并且你并未手动配置任何数据库连接的Bean,那么SpringBoot就会自动配置一个使用内存的数据库。

posted @ 2022-07-24 15:49  yudoge  阅读(17)  评论(0编辑  收藏  举报