博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Spring 5 官方文档》18. Web MVC 框架(八)
阅读量:6228 次
发布时间:2019-06-21

本文共 11696 字,大约阅读时间需要 38 分钟。

18.8.5 LocaleChangeInterceptor

您可以通过添加LocaleChangeInterceptor到其中一个处理程序映射来启用更改区域设置(请参见)。它将检测请求中的一个参数并更改区域设置。它呼吁setLocale()LocaleResolver上下文中也存在。以下示例显示,对包含*.view名为的参数的所有资源的调用siteLanguage现在将更改语言环境。因此,例如,对以下URL的请求将会将站点语言更改为荷兰语。

/**/*.view=someController

18.9使用主题

18.9.1主题概述

您可以应用Spring Web MVC框架主题来设置应用程序的整体外观,从而增强用户体验。主题是影响应用程序视觉风格的静态资源(通常是样式表和图像)的集合。

18.9.2定义主题

要在Web应用程序中使用主题,您必须设置接口的 org.springframework.ui.context.ThemeSource实现。该WebApplicationContext 接口扩展ThemeSource,但其代表职责的专用实现。默认情况下,委托将是 org.springframework.ui.context.support.ResourceBundleThemeSource从类路径根目录加载属性文件的实现。要使用自定义ThemeSource 实现或配置基本名称前缀ResourceBundleThemeSource,可以在应用程序上下文中使用保留名称注册一个bean themeSource。Web应用程序上下文将自动检测具有该名称的bean并使用它。

使用时ResourceBundleThemeSource,在一个简单的属性文件中定义一个主题。属性文件列出构成主题的资源。这是一个例子:

=的styleSheet /主题/冷却/ style.css中背景= /主题/冷却/ IMG / coolBg.jpg

属性的键是从视图代码引用主题元素的名称。对于JSP,您通常使用与spring:theme标记非常相似的自定义标签来执行此操作spring:message。以下JSP片段使用上一个示例中定义的主题来自定义外观:

<%@  taglib  prefix = “spring”  uri = “http://www.springframework.org/tags” %>  	 		
“ type = ”text / css“ />
“ > ...

默认情况下,ResourceBundleThemeSource使用空的基本名称前缀。因此,属性文件从类路径的根目录加载。因此,您可以将 cool.properties主题定义放在类路径的根目录下,例如/WEB-INF/classes。它ResourceBundleThemeSource使用标准的Java资源包加载机制,允许主题的全面国际化。例如,我们可以有一个/WEB-INF/classes/cool_nl.properties引用一个特殊的背景图像与荷兰文本。

18.9.3主题解析器

定义主题后,如上一节所述,您决定使用哪个主题。该 DispatcherServlet会寻找一个叫豆themeResolver,以找出 ThemeResolver使用实施。主题解析器的工作方式与a的方式大致相同 LocaleResolver。它检测到用于特定请求的主题,还可以更改请求的主题。以下主题解析器由Spring提供:

表18.5。ThemeResolver实现

描述
FixedThemeResolver 选择一个固定的主题,使用defaultThemeName属性设置。
SessionThemeResolver 主题维护在用户的HTTP会话中。它只需要为每个会话设置一次,但不会在会话之间持久化。
CookieThemeResolver 所选主题存储在客户端的cookie中。

Spring还提供了一个ThemeChangeInterceptor允许使用简单请求参数对每个请求进行主题更改的功能。

18.10 Spring的多部分(文件上传)支持

18.10.1介绍

Spring的内置多部分支持处理Web应用程序中的文件上传。您可以MultipartResolver使用org.springframework.web.multipart包中定义的可插入对象来 启用此multipart支持。Spring提供了一个MultipartResolver 用于,另一个用于Servlet 3.0 multipart请求解析。

默认情况下,Spring没有多部门处理,因为一些开发人员想要自己处理多个部件。通过将多部分解析器添加到Web应用程序的上下文来启用Spring multipart处理。检查每个请求以查看它是否包含多部分。如果没有找到multipart,请求按预期方式继续。如果在请求中找到一个multipart,MultipartResolver则使用在上下文中声明的multipart 。之后,您的请求中的multipart属性被视为任何其他属性。

18.10.2使用Commons FileUpload的MultipartResolver

以下示例显示如何使用CommonsMultipartResolver

<! - 可用属性之一; 最大文件大小(以字节为单位) - >

当然,您还需要将适当的jar放在您的类路径中,以使多部分解析器工作。在这种情况下CommonsMultipartResolver,您需要使用 commons-fileupload.jar

当Spring DispatcherServlet检测到多部分请求时,它会激活已经在上下文中声明的解析器,并交给请求。解析器然后将当前包装HttpServletRequestMultipartHttpServletRequest支持多部分文件上传的内容中。使用它MultipartHttpServletRequest,您可以获取有关此请求所包含的多部分的信息,实际上可以在控制器中自己访问多部分文件。

18.10.3在Servlet 3.0中使用MultipartResolver

为了使用的Servlet 3.0基于多解析,您需要标记 DispatcherServlet"multipart-config"的部分web.xml,或用 javax.servlet.MultipartConfigElement在编程的Servlet注册,或在自定义Servlet类的情况下,可能与javax.servlet.annotation.MultipartConfig 你的Servlet类注解。需要在Servlet注册级别应用最大大小或存储位置等配置设置,因为Servlet 3.0不允许从MultipartResolver完成这些设置。

一旦使用上述方法之一启用了Servlet 3.0 multipart解析,您可以添加StandardServletMultipartResolver到Spring配置:

18.10.4以表单处理文件上传

完成MultipartResolver工作后,请求像其他任何一样处理。首先,创建一个带有文件输入的表单,允许用户上传表单。编码属性(enctype="multipart/form-data")允许浏览器知道如何将表单编码为多部分请求:

 	 		上传文件请</ title> 	</ head> 	 		

请上传文件

下一步是创建一个处理文件上传的控制器。该控制器非常类似于,除了我们使用MultipartHttpServletRequestMultipartFile在方法参数中:

@Controller public  class FileUploadController {	@PostMapping(“/ form”)	 public String handleFormUpload( @RequestParam(“name”) String name,			 @RequestParam(“file”) MultipartFile文件){		if(!file.isEmpty()){			 byte [] bytes = file.getBytes();			//存储字节某处			返回 “redirect:uploadSuccess” ;		}		返回 “redirect:uploadFailure” ;	}}

注意@RequestParam方法参数如何映射到表单中声明的​​输入元素。在这个例子中,没有什么是完成的byte[],但实际上你可以将它保存在数据库中,将它存储在文件系统上,等等。

当使用Servlet 3.0多部分解析时,您也可以使用javax.servlet.http.Part方法参数:

@Controller public  class FileUploadController {	@PostMapping(“/ form”)	 public String handleFormUpload( @RequestParam(“name”) String name,			 @RequestParam(“file”)零件文件){		InputStream inputStream = file.getInputStream();		//将上传文件的字节存储在某处		返回 “redirect:uploadSuccess” ;	}}

18.10.5处理来自编程客户端的文件上传请求

也可以在RESTful服务方案中从非浏览器客户端提交多部分请求。所有上述示例和配置也适用于此。然而,与通常提交文件和简单表单字段的浏览器不同,编程客户端还可以发送特定内容类型的更复杂数据,例如具有文件的多部分请求,第二部分使用JSON格式的数据:

POST / someUrlContent-Type:multipart / mixed--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp内容处理:表单数据; NAME =“元数据”Content-Type:application / json; 字符集= UTF-8内容传输编码:8bit{	“名称”:“值”}--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp内容处理:表单数据; NAME =“文件的数据”; 文件名= “file.properties”Content-Type:text / xml内容传输编码:8bit...文件数据...

您可以使用@RequestParam("meta-data") String metadatacontroller method参数访问名为“meta-data”的部分。但是,您可能更喜欢接受从请求部分正文中的JSON格式数据初始化的强类型对象,非常类似于@RequestBody在非帮助下将非多部分请求的正文转换为目标对象的方式HttpMessageConverter

您可以使用@RequestPart注释而不是@RequestParam注释用于此目的。它允许您通过HttpMessageConverter考虑多部分的'Content-Type'标题来传递特定多部分的内容:

@PostMapping(“/ someUrl”) public String onSubmit( @RequestPart(“meta-data”)MetaData元数据,		@RequestPart(“file-data”)MultipartFile文件){	// ...}

注意如何MultipartFile使用@RequestParam或 @RequestPart互换访问方法参数。但是,@RequestPart("meta-data") MetaData在这种情况下,该方法参数将被读取为基于其'Content-Type'头部的JSON内容,并在此帮助下进行转换MappingJackson2HttpMessageConverter

18.11处理例外

18.11.1 HandlerExceptionResolver

Spring HandlerExceptionResolver实现处理控制器执行期间发生的意外异常。一个HandlerExceptionResolver有点象异常映射的,你可以在Web应用程序描述符定义web.xml。但是,它们提供了一种更灵活的方法。例如,它们提供有关在抛出异常时正在执行哪个处理程序的信息。此外,处理异常的编程方式可以在请求转发到另一个URL之前提供更多的响应选项(与使用Servlet特定的异常映射相同的最终结果)。

除了实现HandlerExceptionResolver接口,这只是一个实现resolveException(Exception, Handler)方法和返回的问题 ModelAndView,您还可以使用提供的SimpleMappingExceptionResolver或创建 @ExceptionHandler方法。将SimpleMappingExceptionResolver让您采取可能被抛出的异常的类名,并将它映射到视图名。这在功能上等同于Servlet API的异常映射功能,但也可以从不同的处理程序实现更精细的异常映射。@ExceptionHandler另一方面,注释可以用于应该调用来处理异常的方法。这样的方法可以定义在本地内部,@Controller或者可以在@Controller类中定义时应用于许多类 @ControllerAdvice。以下部分将对此进行更详细的解释。

18.11.2 @ExceptionHandler

HandlerExceptionResolver接口和SimpleMappingExceptionResolver 实现允许您在转发到这些视图之前将异常与声明性地映射到特定视图以及一些可选的Java逻辑。然而,在某些情况下,特别是在依赖于@ResponseBody方法而不是视图分辨率的情况下,直接设置响应的状态并可选地将错误内容写入响应主体可能会更为方便。

你可以用@ExceptionHandler方法来做到这一点。当在控制器内声明时,这种方法适用于由@RequestMapping该控制器(或其任何子类)的方法引发的异常。您也可以@ExceptionHandler@ControllerAdvice类中声明一个方法, 在这种情况下,它可以处理@RequestMapping 来自多个控制器的方法的异常。下面是一个控制器局部@ExceptionHandler方法的例子 :

@Controller public  class SimpleController {	// @RequestMapping方法省略...	@ExceptionHandler(IOException.class)	 public ResponseEntity 
handleIOException(IOException ex){ // prepare responseEntity return responseEntity; }}

@ExceptionHandler值可以设置为一个异常类型的数组。如果抛出与列表中的一个类型匹配的异常,@ExceptionHandler则将调用注释与匹配的方法。如果未设置注释值,则使用列为方法参数的异常类型。

与使用@RequestMapping注释注释的标准控制器方法非常相似,方法的方法参数和返回值@ExceptionHandler可以是灵活的。例如,HttpServletRequest可以在Servlet环境中访问。返回类型可以是一个String,它被解释为一个视图名称,一个ModelAndView对象,一个ResponseEntity或者你也可以添加@ResponseBody一个方法返回值转换为消息转换器并写入响应流。

18.11.3处理标准Spring MVC异常

Spring MVC可能会在处理请求时引发许多异常。根据需要, SimpleMappingExceptionResolver可以轻松地将任何异常映射到默认错误视图。但是,在使用以自动方式解释响应的客户端时,您将需要在响应中设置特定的状态代码。根据引发的异常,状态代码可能会指示客户端错误(4xx)或服务器错误(5xx)。

DefaultHandlerExceptionResolverSpring MVC异常转换为特定的错误状态代码。它默认注册了MVC命名空间,MVC Java配置,还有DispatcherServlet(即不使用MVC命名空间或Java配置时)。下面列出了这个解析器处理的一些异常和相应的状态代码:

例外 HTTP状态码
BindException 400(不良要求)
ConversionNotSupportedException 500内部服务器错误)
HttpMediaTypeNotAcceptableException 406(不可接受)
HttpMediaTypeNotSupportedException 415(不支持的媒体类型)
HttpMessageNotReadableException 400(不良要求)
HttpMessageNotWritableException 500内部服务器错误)
HttpRequestMethodNotSupportedException 405(不允许方法)
MethodArgumentNotValidException 400(不良要求)
MissingPathVariableException 500内部服务器错误)
MissingServletRequestParameterException 400(不良要求)
MissingServletRequestPartException 400(不良要求)
NoHandlerFoundException 错误(404)
NoSuchRequestHandlingMethodException 错误(404)
TypeMismatchException 400(不良要求)

DefaultHandlerExceptionResolver通过设置响应的状态透明地工作。但是,您的应用程序可能需要为每个错误响应添加开发人员友好的内容,例如提供REST API时,不会将任何错误内容写入响应正文。你可以准备一个ModelAndView 和渲染通过视图解析错误内容-通过配置,即ContentNegotiatingViewResolverMappingJackson2JsonView,等等。但是,您可能更喜欢使用@ExceptionHandler方法。

如果您喜欢通过@ExceptionHandler方法编写错误内容,可以ResponseEntityExceptionHandler改为扩展 。这是提供处理标准Spring MVC异常和返回@ControllerAdvice@ExceptionHandler方法的类的方便基础 ResponseEntity。这允许您自定义响应并使用消息转换器写入错误内容。有关ResponseEntityExceptionHandler详细信息,请参阅 javadocs。

18.11.4 REST控制器异常处理

一个@RestController可以使用@ExceptionHandler返回一个方法, ResponseEntity在响应的主体既提供响应状态和错误的详细信息。这些方法也可以被添加到@ControllerAdvice 用于子集或所有控制器的异常处理的类中。

一个常见的要求是在响应的正文中包含错误详细信息。Spring不会自动执行此操作(尽管Spring Boot),因为响应主体中的错误详细信息的表示是特定于应用程序的。

希望在响应体中实现具有错误详细信息的全局异常处理策略的应用程序应考虑扩展抽象基类ResponseEntityExceptionHandler,为Spring MVC引发的异常提供处理,并提供钩子来自定义响应体以及处理其他异常。只需将扩展类声明为一个Spring bean并用它进行注释@ControllerAdvice。有关详细信息,请参阅ResponseEntityExceptionHandler

18.11.5使用@ResponseStatus注释业务异常

可以注释业务异常@ResponseStatus。当异常提出时,ResponseStatusExceptionResolver通过相应地设置响应的状态来处理它。默认情况下,DispatcherServlet寄存器 ResponseStatusExceptionResolver,它是可用。

18.11.6自定义默认Servlet容器错误页面

当响应的状态设置为错误状态代码并且响应的正文为空时,Servlet容器通常会呈现HTML格式的错误页面。要自定义容器的默认错误页面,可以在其中声明一个<error-page> 元素web.xml。直到Servlet 3,该元素必须映射到特定的状态代码或异常类型。从Servlet 3开始,不需要映射错误页面,这意味着指定的位置定制了默认的Servlet容器错误页面。

/ error

请注意,错误页面的实际位置可以是容器中的JSP页面或其他一些URL,包括通过一种@Controller方法处理的页面:

编写错误信息时,HttpServletResponse可通过控制器中的请求属性访问状态码和设置的错误信息 :

@Controller public  class ErrorController {	@RequestMapping(path =“/ error”,produce = MediaType.APPLICATION_JSON_UTF8_VALUE)	@ResponseBody	 public Map 
handle(HttpServletRequest request){ Map
map = new HashMap
(); map.put(“status”,request.getAttribute(“javax.servlet.error.status_code”)); map.put(“reason”,request.getAttribute(“javax.servlet.error.message”)); 返回地图; }}

或在JSP中:

<%@  page  contentType = “application / json”  pageEncoding = “UTF-8” %> { 	status:<% = request.getAttribute(“javax.servlet.error.status_code”) %>,	reason:<% = request。 getAttribute(“javax.servlet.error.message”) %> }

18.12网络安全

在项目提供的功能,以防止恶意攻击Web应用程序。请参阅 , 以及 。请注意,使用Spring Security来保护应用程序并不一定需要所有功能。例如,CSRF保护可以通过添加CsrfFilter和配置 CsrfRequestDataValueProcessor来添加。参见  示例。

另一个选择是使用专门用于Web Security的框架。 是一个这样的框架,并与Spring MVC集成。

18.13关于配置支持的公约

对于很多项目,坚持既定的约定和合理的默认值就是它们(项目)所需要的,而Spring Web MVC现在已经明确地支持约定的配置。这意味着如果您建立了一组命名约定等等,您可以大幅度减少设置处理程序映射,查看解析器,ModelAndView实例等所需的配置量 。这对于快速原型,并且如果您选择将其推向生产,还可以在代码库中提供一定程度的(始终如一的)一致性。

公约超配置支持解决了MVC的三个核心领域:模型,视图和控制器。

18.13.1 Controller ControllerClassNameHandlerMapping

ControllerClassNameHandlerMapping班是一个HandlerMapping使用惯例来确定请求的URL和之间的映射实现Controller是要处理这些请求的情况。

考虑以下简单的Controller实现。特别注意 课程名称

public  class  ViewShoppingCartController  implements Controller {	public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response){		 //实现对于这个例子来说不是很重要...	}}

以下是相应的Spring Web MVC配置文件的代码段:

<! - 根据需要注入依赖关系... - >

ControllerClassNameHandlerMapping找出所有的处理程序(或 Controller在其应用上下文定义的)豆和剥离Controller掉,以限定其处理程序映射的名称。因此,ViewShoppingCartController映射到 /viewshoppingcart*请求URL。

我们再来看一些更多的例子,使中心思想变得熟悉。(注意URL中的全部小写,与骆驼Controller类的类名相反)。

  • WelcomeController映射到/welcome*请求URL
  • HomeController映射到/home*请求URL
  • IndexController映射到/index*请求URL
  • RegisterController映射到/register*请求URL

MultiActionController处理程序类的情况下,生成的映射稍微复杂一点。以下Controller示例中的名称被假定为实现MultiActionController

  • AdminController映射到/admin/*请求URL
  • CatalogController映射到/catalog/*请求URL

如果你按照你的命名的惯例Controller实现的 xxxController,将ControllerClassNameHandlerMapping节省您定义和维护一个潜在的沉闷一长串SimpleUrlHandlerMapping(或类似的东西)。

ControllerClassNameHandlerMapping类扩展AbstractHandlerMapping基类,所以你可以定义HandlerInterceptor实例和一切,就像你与许多其他HandlerMapping的实现。

转载自

你可能感兴趣的文章
磊哥评测之数据库:腾讯云MongoDB vs自建
查看>>
Git 常用命令集
查看>>
小心钱财不翼而飞!微信绑定银行卡的有必要点击这个按钮!
查看>>
组件调用错误,路径问题
查看>>
Python 基础起步 (九) 条件语句 if elif else 其实很简单
查看>>
Hello, Node.js!
查看>>
JavaWEB开发14——ajax
查看>>
Vue2.0 + ElementUI 手写权限管理系统后台模板(二)——权限管理
查看>>
利用AudioContext来实现网易云音乐的鲸鱼音效
查看>>
简述原型链是什么,有什么用处?若想访问一个对象的原型,应该使用什么方法?...
查看>>
HBuilder开发WAP2APP增加扫一扫功能
查看>>
程序员选电脑,你会不会买Mac?
查看>>
JS 里的数据类型转换
查看>>
python大佬养成计划----正则表达式
查看>>
JS原型与原型链总结篇
查看>>
mybatis缓存机制与陷阱
查看>>
【CSS】CSS常用技巧
查看>>
IO多路复用(二) -- select、poll、epoll实现TCP反射程序
查看>>
ECMAScript6(11):Set 与 Map
查看>>
Spring
查看>>