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,设置DispatcherServlet
的MultipartConfig
,并且定义StandardServletMultipartResolver
。
Controller默认参数解析逻辑
如果一个方法参数没有匹配在这个表格中的前面的任何值,并且它是一个简单类型,那么它被@RequestParam
注解来解析,否则,它被@ModelAttribute
注解解析。
解析:在Controller方法中可以接收一些特殊参数,比如
HttpServletRequest
,HttpEntity
,详情在官方文档中的一个表格里。但如果一个参数不是表格里定义的,如果它是一个简单类型(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.class
或RemoteException.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
方法进行测试
-
直接抛出
IOException
,但上面的方法只接收它的两个子类,所以没有走@ExceptionHandler
@RequestMapping("/crashRootExceptionDirectly") public String crashRootExceptionDirectly() throws IOException { throw new IOException("ioexception"); }
-
直接抛出子类异常,毫无疑问,会正常的走
@ExceptionHandler
@RequestMapping("/crashSubExceptionDirectly") public String crashSubExceptionDirectly() throws FileSystemException { throw new FileSystemException("filesystem exception"); }
走到了
@ExceptionHandler
返回值中设置好的异常显示界面 -
采用
IOException
包装子类异常,最终,@ExceptionHandler
中接到的方法是父类异常@RequestMapping("/crashSubExceptionWrappedInRootException") public String crashSubExceptionWrappedInRootException() throws IOException { throw new IOException(new FileSystemException("filesystem exception")); }
但可以通过
getCause
来获取被包装的子异常 -
采用毫不相干的异常包装
FileSystemException
,最终,@ExceptionHandler
中接收到的是被包装异常@RequestMapping("/crashSubExceptionWrappedInRuntimeException") public String crashSubExceptionWrappedInRuntimeException() { throw new RuntimeException(new FileSystemException("filesystem exception")); }
总结就是,在Controller方法发生异常时,SpringMVC(或者说它的HandlerAdapter)除了会考虑这个异常的直接类型之外,还会考虑它的cause
的类型。一个例外就是当一个@ExceptionHandler
方法由于cause
类型匹配而被选中处理异常时,若它的方法参数就是包装异常的类型,那么被传入到异常对象是包装异常示例。
SpringBoot自动配置
SpringBoot的自动配置功能会基于你添加的Jar依赖来尝试自动的配置你的Spring应用。举例来说,如果HSQLDB
在你的classpath下,并且你并未手动配置任何数据库连接的Bean,那么SpringBoot就会自动配置一个使用内存的数据库。