快捷搜索:  as

Spring基础(四)

16. Web MVC 框架

16.1 Spring Web MVC 框架先容

Spring Web 模型-视图-节制器(MVC) 框架是环抱 DispatcherServlet而设计的,其支持可设置设置设备摆设摆设的 handler 映射,视图解析,本地化、时区和主题的解析以及文件上传的功能。DispatcherServlet 认真将哀求分发到不合的 handler。默认的 handler 经由过程@Controller 和 @RequestMapping评释,供给多种机动的处置惩罚措施。若加上 @PathVariable 评释和其他帮助功能,你也可用应用 @Controller 机制来创建 RESTful web 站点和利用法度榜样。

用 Spring Web MVC ,你不必要实现框架指定的任何接口或承袭随意率性基类,就可以应用随意率性工具作为敕令工具(或表单工具)。Spring 的数据绑定相称之机动,比如,Spring可以将不匹配的类型作为利用可识别的验证差错,而不是系统差错,以是,你不必要去重复定义一套属性同等而类型是原始字符串的营业逻辑工具,去处置惩罚差错的提交或对字符串进行类型转换。反过来说便是,spring 容许你直接将精确类型的参数绑定到营业逻辑工具。

Spring 的视图解析也相称之机动。完成一个哀求,Controller 平日是认真筹备一个数据模型 Map 和选择一个指定的视图,当然,也支持直接将数据写到相应流里。视图名称的解析是高度可设置设置设备摆设摆设的,可以经由过程文件扩展名、accept header 的 Content-Type、bean 的名称、属性文件或自定义的 ViewResolver 实现来解析。模型(Model,MVC 中的 M),是一个 Map 接口,供给对视图数据的完全抽象,可直接与衬着模版集成,如 JSP,Veloctiy,Freemarker;或直接天生原始数据,或xml、json等其他类型的相应内容。模型 Map 接口只是认真将数据转换为适及款式,如 jsp 哀求属性,velocity 的 model 等。

16.2 The DispatcherServlet

像其他 web MVC 框架一样, Spring web MVC 框架也是基于哀求驱动,环抱一个核心 Servlet 转发哀求到对应的 Controller 而设计的,供给对web 法度榜样开拓的根基的支持。然而 Spring 的 DispatcherServlet 并不仅仅拥有这些,由于 Spring MVC 框架集成了 Spring IOC 容器,是以,Spring MVC 可以应用 Spring 供给的其他功能。

Spring Web MVC 哀求处置惩罚的宏不雅图

DispatcherServlet 承袭了 HttpServlet ,是一个真实的 Servlet,是以可以在 web.xml 文件声明。别的你必要应用 url 匹配元件指定 DispatcherServlet 处置惩罚的哀求。如下例子,应用了标准 java EE Servlet 设置设置设备摆设摆设,设置设置设备摆设摆设了一个 DispatcherServlet的声明和匹配 url 元件:

example

org.springframework.web.servlet.DispatcherServlet

1

example

/example/*

在刚才设置设置设备摆设摆设的例子中,所有以 /example 开始的哀求都邑被名为 example 的 DispatcherServlet 所处置惩罚。在 Servlet 3.0+ 情况,也可以以编程要领设置设置设备摆设摆设上述 DispatcherServlet。如下代码与上述 web.xml 设置设置设备摆设摆设例子等效:

public class MyWebApplicationInitializer implements WebApplicationInitializer {

@Override

public void onStartup(ServletContext container) {

ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet());

registration.setLoadOnStartup(1);

registration.addMapping("/example/*");

}

}

上述的操作仅仅是开启了 Spring Web MVC 之旅的第一步,现在你必要设置设置设备摆设摆设 Spring Web MVC 所应用到的各类 bean(这不在本节评论争论范围)。

在Spring里可以获取到 ApplicationContext 实例,在 web MVC 框架,每一个 DispatcherServlet 都拥有自己的 WebApplicationContext,这个 WebApplicationContext 承袭了根 WebApplicationContext 定义的所有 bean.

DispatcherServlet 在初始化时,Spring MVC 会查找 web 利用 WEB-INF 目录下的[servlet-name]-servlet.xml 并创建在此文件定义的 bean,若在全局范围里有一个名称相同的 bean,全局范围的 bean 会被覆盖掉落。

golfing

org.springframework.web.servlet.DispatcherServlet

1

golfing

/golfing/*

上述设置设置设备摆设摆设,要求利用法度榜样在 WEB-INF 目录下有一个 golfing-servlet.xml 文件,在这个文件里,会包孕 Spring MVC 的所有组件(beans)。你可以经由过程定义 servlet 初始化参数来改变[servlet-name]-servlet.xml 文件的路径,如下:

contextConfigLocation

/WEB-INF/root-context.xml

dispatcher

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

1

dispatcher

/*

org.springframework.web.context.ContextLoaderListener

6.2.1 WebApplicationContext 的专用 bean

DispatcherServlet 应用了其专用的 bean 来处置惩罚哀乞降衬着视图。这些 bean 是 Spring 的组成部分之一,你可以选择在 WebApplicationContext设置设置设备摆设摆设所应用一个或多个专用的bean。当然,你并不必要一开始就去设置设置设备摆设摆设这些专用的 bean,由于在你不设置设置设备摆设摆设这些 bean时,Spring 会掩护一系列默认的 bean。首先我们看一下 DispatcherServlet 依附了哪些专用的 bean,后续再作详解。

Bean 类型

解释

HandlerMapping

将传入的哀求映射到处置惩罚器,与一系列基于各类前提的 pre- 和 post- 处置惩罚器,这些处置惩罚器根据 HandlerMapping 实现的不合而会有所差异。

HandlerAdapter

赞助 DispatcherServlet 去调用哀求所映射的 handler,不管hadler 终极是否会被调用,这个处置惩罚历程都邑存在的。比如,调用评释节制器前必要解析各类 annotations。是以,HandlerAdapter 的主要目的便是从 DispatcherServlet 中樊篱这些处置惩罚细节。

HandlerExceptionResolver

将非常映射到指定视图,也支持自定义加倍繁杂的非常处置惩罚流程

ViewResolver

将合理的视图名称解释为真实的视图类型

ThemeResolver

解释 web 法度榜样可用的主题,比如,供给个性化的结构

MultipartResolver

解释 multi-part 哀求,比如,在 html form 里支持文件上传

16.2.2 默认的 DispatcherServlet 设置设置设备摆设摆设

如上一节所说,每一个 DispatcherServlet 都保持了一系列默认的实现。这些默认实现的信息保存在 org.springframework.web.servlet 包里的 DispatcherServlet.properties 文件。

只管所有专用的 bean 都有其合理的默认值。迟早你也必要根据实际去自定义这些 bean 的中一个或多个属性值。例如一种很常见的自定义利用,设置设置设备摆设摆设一个 InternalResourceViewResolver,其 prefix 为视图文件的父文件夹。

不管这些默认细节若何实现,在这里都必要清楚一个观点——一旦在 WebApplicationContext 设置设置设备摆设摆设自己专用的 bean,就有效覆盖了原有一系列默认的实现,至少也会作为这个专用 bean 的一个实例。

16.2.3 DispatcherServlet 处置惩罚顺序

在你建立一个 DispatcherServlet 之后,并处置惩罚一个传进来的哀求时,DispatcherServlet 会按照以下顺序年来处置惩罚这个哀求:

探求 WebApplicationContext,并将 WebApplicationContext作为一个属性绑定到哀求里,以便节制器或其他原件在后续中应用。默认会以 DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE 键绑定到哀求里。

将本地化解析器绑定到哀求里,以便在处置惩罚这个哀求时,原件可以解析到客户真个地区(为了衬着视图,筹备日期等)。假如你不必要本地化解析器,可以轻忽这个步骤。

将主题解析其绑定到哀求里,让原件(如视图)抉择去应用哪一种主题。假如你不必要应用主题,可以轻忽这个步骤。

假如你指定一个 multipart file 解析器,会反省这个哀求包孕 multiparts 哀求。当发清楚明了 multiparts,这个哀求会被封装为 MultipartHttpServletRequest 工具,供给给后续原件处置惩罚。

探求相宜的 handler。若何找到这个 handler,履行与这个 handler 关联的履行链,目的是筹备一个 model 或 衬着。

假如返回一个 model,衬着相对应的视图。反之(可能是由于 pre- 或 post- 处置惩罚器拦截了这个哀求,也可能是权限问题),便不衬着任何视图,由于这个哀求可能已履行完成。

handler 非常解析是在 WebApplicationContext 声明的,接管在上述处置惩罚历程抛出的非常。应用非常解析器,你可以根据非常信息自定义其处置惩罚要领。

16.3 实现节制器(Controller)逻辑

Controller层面主如果节制web哀求的路由和视图解析,Spring对付Controller的支持是十分完善的,我们在定义路由逻辑的时刻并要求我们承袭和实现某个类,只必要添加Spring的评释信息就可以做到。下面我么你先看一个简单的Controller定义逻辑:

@Controller

public class HelloWorldController {

@RequestMapping("/helloWorld")

public String helloWorld(Model model) {

model.addAttribute("message", "Hello World!");

return "helloWorld";

}

}

如你所见,@Controller 和 @RequestMapping 容许机动的设置设置设备摆设摆设措施署名。在上述例子中,helloWorld 措施吸收一个 Model 参数,并返回一个视图名称,当然也容许添加措施入参和返回不合类型的值,这些内容将会在后面解释。@Controller 、@RequestMapping 和其他一些功能评释组成了 Spring MVC 实现的根基,这一节将会谈到这些组成的评释和在 Servlet 情况的普遍用法。

16.3.1 应用 @Controller 定义节制器

@Controller 注解了被评释类的办事角色——节制器。Spring 不必要去承袭任何 Controller 的基类或引用随意率性的 Servlet API。当然了,若何你必要的, 你仍旧可以引用 Servlet API。

@Controller 评释定义了被评释类的原型,注解了评释类的办事角色。dispatcher 会扫描这些被 @Controller 标记的类并检测 @RequestMapping 标记的措施(见下一节)。

你可以在 dispatcher 高低文显式定义节制器 bean,不过,为了与 Spring 支持在类路径上检测 bean 并自动注册这些 bean 定义 维持同等,@Controller 大概容许自动检测。

要开启评释节制器的扫描功能,必要在你的设置设置设备摆设摆设里添加组件扫描元件。如下 xml 所示,可以应用 spring-context 模式开启此扫描功能:

6.3.2 应用 @RequestMapping 映射哀求

你可以在类或指定 handler 措施上,应用 @RequestMapping 评释来映射 URL,如 /appointments。定义在类上以为这该类下的所有的措施级其余@RequestMapping将以类上定义的路径为根基path前缀,假如类上没有定义的话,将直接应用措施级其余value值作为匹配的path。

@Controller

@RequestMapping("/appointments")

public class AppointmentsController {

private final AppointmentBook appointmentBook;

@Autowired

public AppointmentsController(AppointmentBook appointmentBook) {

this.appointmentBook = appointmentBook;

}

@RequestMapping(method = RequestMethod.GET)

public Map get() {

return appointmentBook.getAppointmentsForToday();

}

@RequestMapping(value="/new", method = RequestMethod.GET)

public AppointmentForm getNewForm() {

return new AppointmentForm();

}

}

例子中,在多处地方应用 @RequestMapping。第一个用在了类上,表示@RequestMapping 这个节制器下的所有 handler 措施都是相对 /appointments 路径而言的。get() 措施对 @RequestMapping 做了进一步的细化 —— 此措施只接管 GET 哀求要领(@RequestMapping 默认匹配所有的 http 措施),换句话说便是 /appointments 的GET 哀求会调用这个措施; add() 措施也做一个类似的细化; getNewForm() 措施在 RequestMapping 上组合定义了 http 措施和路径,是以此措施会处置惩罚 appointments/new 的 GET 哀求。

URI 模版模式

URI 模版是一个类似于 URI 的字符串,此中包孕了一个或多个变量。当你将这些变量调换掉落市,就变回了 URI可在措施入参上应用评释 @PathVariable 绑定 URI 的模版参数:

@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)

public String findOwner(@PathVariable String ownerId, Model model) {

Owner owner = ownerService.findOwner(ownerId);

model.addAttribute("owner", owner);

return "displayOwner";

}

URI 模版 " /owners/{ownerId}" 指定了参数 owernId。当节制器处置惩罚这个哀求时,会将 URI 中匹配的部分赋值给 owernId 变量。如,当传入 /owners/fred 哀求时,owernId 的值便是 fred。

在处置惩罚 @PathVariable 评释时,Srping MVC 是根据名称来匹配 URI 模版变量的。你可以在评释里指定这个名称:

@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)

public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {

// implementation omitted

}

假如URI 模版变量名和入参名同等,可以省略这个细节。只要你的代码不是不带调试信息的编译,Spring MVC 将匹配入参名和 URI 变量名。

一个措施可以有随意率性个 @PathVariable 评释。

@RequestMapping(value="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET)

public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {

Owner owner = ownerService.findOwner(ownerId);

Pet pet = owner.getPet(petId);

model.addAttribute("pet", pet);

return "displayPet";

}

URI 模版可以组合类型和参数路径的 @RequestMapping。是以,findPet 可以处置惩罚类似 /owners/42/pets/21 的URI 。

@Controller

@RequestMapping("/owners/{ownerId}")

public class RelativePathUriTemplateController {

@RequestMapping("/pets/{petId}")

public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {

// implementation omitted

}

}

@PathVariable 参数可所以随意率性的简单类型(如 int,long,Date 等),Spring 会自动将其进行类型转换,转换掉足会抛出 TypeMismatchException。你也可以注册支持解析其他数据类型,这个内容后面会涉及到。

在 URI 模版上应用正则表达式

有时,在URI 模版变量里,你会必要用到加倍正确的节制。比如 "/spring-web/spring-web-3.0.5.jar" 这样的URI,该若何拆分成多个部分?

@RequestMapping 评释支持在 URI 模版变量里应用正则表达式。语法 {变量名:正则表达式},第一个部分定义变量的名称,第二部分是正则表达式。如

@RequestMapping("/spring-web/{symbolicName:[a-z-]}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]}")

public void handle(@PathVariable String version, @PathVariable String extension) {

// ...

}

}

路径模式对照

当一个 URL 与多个模式匹配时,会设法找出最详细的那一个路径。

当模式中的 URI 模版变量和通配符的数量相对较少,会觉得其相对详细。如:/hotels/{hotel}/* 相对 /hotels/{hotel}/** 加倍相宜,由于 /hotels/{hotel}/* 只有一个URI 模版变量和一个通配符,而 hotels/{hotel}/**` 有一个 URI 模版变量和两个通配符。

当两个模式中的 URI 模版变量和通配符数量相同时,更具体的那一个会觉得相对得当。如 /foo/bar* 比 /foo/* 更为具体。

一些额外的分外规定:

随意率性模式都比默认全匹配 /** 模式详细。如:/api/{a}/{b}/{c} 比 /** 加倍详细。

随意率性不包孕两个通配符的模式都比前缀模式(如 /public/) 加倍详细。/public/path3/{a}/{b}/{c} 比 /public/ 加倍详细。

路径模式的后缀匹配

Spring MVC 默认自动履行 "." 的后缀匹配,以是当一个节制器匹配 /person 时,其也隐式匹配 /person.。这样的设计容许经由过程文件扩展名来阐明内容的类型名比如 /person.pdf, /person.xml 等。然而,这里会有一个常犯的陷阱,当路径着末的片段是 URI 模版变量时(如 /person/{id}),哀求 /person/1.json 可以精确匹配路径,变量 id=1,拓展名为 json,可当 id 自身包孕 . (如 /person/joe@email.com),那匹配结果就不是我们所期望的,显然 ".com" 不是文件扩展名。

办理这个问题的精确措施是设置设置设备摆设摆设 Spring MVC 只对注册的文件扩展名做后缀匹配,这要求内容(扩展名)协商好。

矩阵变量

矩阵变量是我之前完全没有打仗过的一种内容,后来读了文档之后才知道竟然还有这种操作,这里也分外记录一下矩阵变量。

矩阵变量可以呈现在任何path上面,矩阵变量之间经由过程";"(英文分号)来区分,举个例子"/cars;color=red;year=2012",矩阵变量假如有多个值的话,值之间可以经由过程,(英文逗号)来瓜分,例如"color=red,green,blue"。

假如一个URL中呈现矩阵变量的话,那么哀求映射模式必须用URI模板表示它们。这确保了无论矩阵变量是否存在,以及它们以什么顺序被供给,哀求都能被精确匹配。

// GET /pets/42;q=11;r=22

@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET)

public void findPet(@PathVariable String petId, @MatrixVariable int q) {

// petId == 42

// q == 11

}

因为所有路径段都可能包孕矩阵变量,是以在某些环境下,您必要更详细地确定变量的预期位置:

// GET /owners/42;q=11/pets/21;q=22

@RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)

public void findPet(

@MatrixVariable(value="q", pathVar="ownerId") int q1,

@MatrixVariable(value="q", pathVar="petId") int q2) {

// q1 == 11

// q2 == 22

}

-----------------------------------------

// GET /pets/42

@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET)

public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {

// q == 1

}

------------------------------------------

// GET /owners/42;q=11;r=12/pets/21;q=22;s=23

@RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)

public void findPet(

@MatrixVariable Map matrixVars,

@MatrixVariable(pathVar="petId"") Map petMatrixVars) {

// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]

// petMatrixVars: ["q" : 11, "s" : 23]

}

默认环境下矩阵变量是不被spring激活的,假如你想应用矩阵变量的话,你必要在设置设置设备摆设摆设Spring的时刻激活一下:

可破费的媒体类型

你可以指定一系列可破费的媒体类型来压缩主要映射。这样只用当 Content-Type 哀求头匹配可破费的媒体类型,才觉得这个哀求是可映射的。如:

@Controller

@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")

public void addPet(@RequestBody Pet pet, Model model) {

// 实现省略

}

哀求参数和头字段值

你可以经由过程哀求参数前提来压缩哀求匹配范围,如应用 "myParam", "!myParam", 或 "myParam=myValue"。前两种环境表示 存在/不存在,第三种指定了参数值。如下给出指定参数值的例子:

@Controller

@RequestMapping("/owners/{ownerId}")

public class RelativePathUriTemplateController {

@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue")

public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {

// 省略实现

}

}

类似的,头字段也支持 存在/不存在 和基于指定头字段值的匹配:

@Controller

@RequestMapping("/owners/{ownerId}")

public class RelativePathUriTemplateController {

@RequestMapping(value = "/pets", method = RequestMethod.GET, headers="myHeader=myValue")

public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {

// 省略实现

}

}

16.3.3 定义 @RequestMapping 处置惩罚措施

@RequestMapping 处置惩罚措施容许异常机动的署名,其支持措施参数和返回值(在这一节谈到)。除了 BindingResult 参数,其他类型参数顺序随意.

如下是可以支持的措施参数:

Request 或 response 工具 (Servlet API). 选择随意率性指定的 request 或 response 类型,如ServletRequest o或 HttpServletRequest.

Session 工具 (Servlet API):必如果 HttpSession 类型. 这种类型的参数会强制相宜 session 的存在。是以,这个参数永世不会为 null。

org.springframework.web.context.request.WebRequest 或 org.springframework.web.context.request.NativeWebRequest.容许经由过程哀求参数造访和 request/session 属性造访

java.util.Locale 给当前哀求本地化,取决于最详细的本地化解析器,实际上取决与是 Servlet 情况设置设置设备摆设摆设的 LocaleResolver 。

java.io.InputStream / java.io.Reader 可造访哀求的内容。这是 Servlet API 裸露的原生 InputStream/Reader 。

java.io.OutputStream / java.io.Writer 用于 孕育发生 response 的内容。这是 Servlet API 裸露的原生 OutputStream/Writer.

org.springframework.http.HttpMethod 可造访 HTTP 哀求措施。

@PathVariable 评释参数,可造访 URI 模版变量。

@MatrixVariable 矩阵变量

@RequestParam 评释参数,可造访指定 Servlet request 参数。参数值会被转换为措施参数的类型。

@RequestHeader 评释参数,可造访指定 Servlet request 的 HTTP 头字段。参数值会被转换为措施参数的类型。

@RequestBody 评释参数,可造访 HTTP 哀求体。参数值应用 HttpMessageConverter 转换为措施参数类型

@RequestPart 评释参数,可造访 "multipart/form-data" 哀求的内容。

HttpEntity 参数,可造访 Servlet request 的HTTP头和内容。

以下是可支持的返回类型

一个ModelAndView工具,该模型隐式地富厚了敕令工具和@ModelAttribute评释引用数据造访器措施的结果

一个Model工具,此中view的名字是经由过程RequestToViewNameTranslator隐式声明的,该模型隐式地富厚了敕令工具和@ModelAttribute评释引用数据造访器措施的结果

一个Map工具,内容跟model工具基础同等。

一个View工具,此中model的信息隐式地富厚了敕令工具和@ModelAttribute评释引用数据造访器措施的结果。

一个String工具,内容基础跟View工具的内容差不多。

返回void,假如措施内容已经自己处置惩罚了response内容或者想依附RequestToViewNameTranslator来天生对应的view名称的话,这种环境下可以返回void

假如措施本身被@ResponseBody注释了,这时刻返回的类型会被直接写入到相应体里面,这时刻返复书息会根据措施声明的类型,经由过程HttpMessageConverter来进行转换。

一个HttpHeaders工具,可以经由过程此工具拿到相应头信息。

一个Callable工具,一个异步结果信息。

应用 @RequestParam 将哀求参数绑定到措施参数

在节制器里,应用 @RequestParam 将哀求参数绑定到措施参数。

@Controller

@RequestMapping("/pets")

public class EditPetForm {

@RequestMapping(method = RequestMethod.GET)

public String setupForm(@RequestParam("petId") int petId, ModelMap model) {

Pet pet = this.clinic.loadPet(petId);

model.addAttribute("pet", pet);

return "petForm";

}

}

应用 @RequestParam 的参数默认是必须供给的,当然,你可以指定其为可选的,将 @RequestParam 的 reqired 属性设置 false 即可。(如, @RequestParam(value="id", required=false)).

假如措施参数的类型不是 String,类型转换会自动履行,假如将 @RequestParam 用于 Map 或 MultiValueMap 参数,此参数 map 会添补所有的哀求参数。

应用 @RequestBody 映射哀求体

@RequestBody 评释参数表示该参数将与 HTTP 哀求体绑定。例子:

@RequestMapping(value = "/something", method = RequestMethod.PUT)

public void handle(@RequestBody String body, Writer writer) throws IOException {

writer.write(body);

}

@RequestBody 措施参数可添加 @Valid 评释,被评释的参数会应用设置设置设备摆设摆设的 Validator 来验证。当应用 MVC 命名空间或 mvc Java 设置设置设备摆设摆设时,利用会自动设置设置设备摆设摆设 JSR-303 验证器(条件是在类路径能找到 JSR-303 的实现)。

类似于 @ModelAttribute 参数,Errors 参数也可用来检测差错。当 Errore 参数没有声明时,或抛出 MethodArgumentNotValidException。此非常会被 DefaultHandlerExceptionResolver 处置惩罚 —— 向客户端发送 400 差错。

应用 @ResponseBody 映射相应体

@ResponseBody 的应用类似于 @RequestBody。此评释用在措施上,用来表示直接将返回数据写到 HTTP 相应体里。留意,不是将数据放到 Model 中,或解析为视图名称。例子:

@RequestMapping(value = "/something", method = RequestMethod.PUT)

@ResponseBody

public String helloWorld() {

return "Hello World";

}

上述例子会将 Hello World 文本写到 HTTP 相应流中。

应用 @RestController 创建 REST 节制器

一种对照常见的场景,节制器实现 REST API,只会返回 JSON、XML 或其他自定义媒体类型。为了方便,你可以在节制器上添加 @RestController 评释,而不是在每一个 @RequestMapping 上应用 @ResponseBody。

@RestController 是一个结合了 @ResponseBody 和 @Controller 的评释。不仅如斯,@RestController 付与了节制器更多的意义,在未来的版本中可能会携带额外的语义。。

应用 HttpEntity

HttpEntity 的用法类似于 @RequestBody 和 @ResponseBody 评释。除了可以造访哀求/相应体,HttpEntity(和特用与相应的子类 ResponseEntity) 还可以造访 request 和 response 的头字段。例子:

@RequestMapping("/something")

public ResponseEntity handle(HttpEntity requestEntity) throws UnsupportedEncodingException {

String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader"));

byte[] requestBody = requestEntity.getBody();

// do something with request header and body

HttpHeaders responseHeaders = new HttpHeaders();

responseHeaders.set("MyResponseHeader", "MyValue");

return new ResponseEntity("Hello World", responseHeaders, HttpStatus.CREATED);

}

上述例子获取了 MyRequestHeader 头字段的值,以字节数组的形式读取了哀求体,随后将 MyRequestHeader 添加到 response,将 Hello World 写到相应流和设置相应状态码为 201(Created).

在措施上应用 @ModelAttribute

@ModelAttribute 可用欲措施或措施参数中。这一部分将先容 @ModelAttribute 在措施中的应用,下一部分先容其在措施啊参数中的应用。

在措施上应用 @ModelAttribute 评释,表示此措施的目的在于添加一个或多个模型属性。这种措施所支持的参数类型与 @RequestMapping 一样,不合的是,其不能直接映射到 request。别的,在同一个节制器里,@ModelAttribute 会在 @RequestMapping 之前调用。

// 添加一个属性

// 措施的返回值会以 "account" 键添加到 model

// 可经由过程 @ModelAttribute("myAccount") 自定义

@ModelAttribute

public Account addAccount(@RequestParam String number) {

return accountManager.findAccount(number);

}

// 添加多个属性

@ModelAttribute

public void populateModel(@RequestParam String number, Model model) {

model.addAttribute(accountManager.findAccount(number));

// 再添加多个……

}

第一种,在措施里隐式添加一个属性并返回;第二种,措施里接管 Model 参数,并将随意率性个属性添加到 Model中。一个节制器可以有多个 @ModelAttribute 措施。在同一个节制器中,所有 @ModelAttribute 措施都邑在 @RequestMapping 措施之前调用。

@ModelAttribute 评释也可用在 @RequestMapping 措施中。这种环境下,@RequestMapping 措施的返回值将解析为模型属性,而不是视图名称。相反,视图名称滥觞于视图名称的约定,就类似于措施返回 void

指定 redirect 和 flash 属性

在重定向 URL 中,所有模型属性默认裸露给 URI 模版变量,剩下的属性(原始类型或原始类型聚拢/数组)会自动拼接到查询参数中。

然而,在一个带评释的节制器中,模型大概包孕了额外的属性(用于衬着,如下拉框属性)。在重定向场景中,要准确节制这些属性,可在 @RequestMapping 措施中声明 RedirectAttributes 类型参数,并往其添加 RedirectView 应用的属性。假如这个节制措施切实着实发生重定向,将应用 RedirectAttributes 的内容,否则应用默认 Model 的内容。

RequestMappingHandlerAdapter 供给了一个 "ignoreDefaultModelOnRedirect" 标志,用来设置在节制措施重定向时,默认Model 的内容是否从不应用。相反,节制器措施应该声明 RedirectAttributes 类型属性,否则会没有任何属性通报给 RedirectView。为了向后兼容,MVC 命名空间和 MVC Java 设置设置设备摆设摆设都将 "ignoreDefaultModelOnRedirect" 设置为 false。可我们照样建议你在新利用里将其设置为 true。

RedirectAttributes 接口也可以用来添加 flash 属性。与其他重定向属性(在重定向 URL 中销毁)不合的是,flash 属性会保存到 HTTP session(是以 flash 属性也不会在 URL 上呈现)。感化于重定向 URL 的节制器里的模型会自动接管这些 flash 属性,之后,flash 属性会从 session 中移除。

应用 @CookieValue 映射 cookie 值

@CookieValue 评释容许将措施参数与HTTP cookie 值绑定。

@RequestMapping("/displayHeaderInfo.do")

public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) {

//...

}

假如措施参数不是 String 类型,类型转换会自动履行

应用 @RequestHeader 映射哀求头字段属性

@RequestHeader 评释容许将措施参数与哀求头字段绑定。

如下一个哀求头字段值的样例:

Hostlocalhost:8080

Accepttext/html,application/xhtml+xml,application/xml;q=0.9

Accept-Languagefr,en-gb;q=0.7,en;q=0.3

Accept-Encodinggzip,deflate

Accept-CharsetISO-8859-1,utf-8;q=0.7,*;q=0.7

Keep-Alive300

如下代码演示了若何获取 Accept-Encoding 和 Keep-Alive 头字段值:

@RequestMapping("/displayHeaderInfo.do")

public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,

@RequestHeader("Keep-Alive") long keepAlive) {

//...

}

应用 @ControllerAdvice 评释增强节制器

@ControllerAdvice 评释可以让实现类经由过程类路径自动检测出来。当应用 MVC 命名空间或 MVC Java 设置设置设备摆设摆设时,此此功能是默认启动的。

带有 @ControllerAdvice 评释的类,可以包孕 @ExceptionHandler、@InitBinder, 和 @ModelAttribute 评释的措施,并且这些评释的措施会经由过程节制器层次利用到所有 @RequestMapping 措施中,而不用逐一在节制器内部声明。

// 利用到所有 @RestController 节制器

@ControllerAdvice(annotations = RestController.class)

public class AnnotationAdvice {}

// 利用到指定包下的节制器

@ControllerAdvice("org.example.controllers")

public class BasePackageAdvice {}

// 利用到指定类型的节制器

@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})

public class AssignableTypesAdvice {}

16.3.4 异步哀求处置惩罚

Spring MVC 引入了基于异步哀求的 Servlet 3。在异步哀求中,节制器措施平日会返回 java.util.concurrent.Callable 工具后再应用一个自力的线程孕育发生返回值,而不是直接返回一个值。同时开释 Servlet 容器的主线程和容许处置惩罚其他哀求。Spring MVC 借助 TaskExecutor ,在一个自力线程中调用 Callable,当 Callable 返回时,将哀求转发到 Servlet 容器并继承处置惩罚 Callable 返回值。例子如下:

@RequestMapping(method=RequestMethod.POST)

public Callable processUpload(final MultipartFile file) {

return new Callable() {

public String call() throws Exception {

// ...

return "someView";

}

};

}

16.3.4 异步哀求处置惩罚

Spring MVC 引入了基于异步哀求的 Servlet 3。在异步哀求中,节制器措施平日会返回 java.util.concurrent.Callable 工具后再应用一个自力的线程孕育发生返回值,而不是直接返回一个值。同时开释 Servlet 容器的主线程和容许处置惩罚其他哀求。Spring MVC 借助 TaskExecutor ,在一个自力线程中调用 Callable,当 Callable 返回时,将哀求转发到 Servlet 容器并继承处置惩罚 Callable 返回值。例子如下:

@RequestMapping(method=RequestMethod.POST)

public Callable processUpload(final MultipartFile file) {

return new Callable() {

public String call() throws Exception {

// ...

return "someView";

}

};

}

异步哀求的别的一种要领,是让节制器返回 DeferredResult 实例。这种环境下,依然是从一个自力线程处置惩罚并孕育发生返回值。然而,Spring MVC 并不知晓这个线程的后续处置惩罚。比如说,这个返回结果可以用来相应某些外部事故(如 JMS 信息,计划义务等)。例子如下:

@RequestMapping("/quotes")

@ResponseBody

public DeferredResult quotes() {

DeferredResult deferredResult = new DeferredResult();

// 将 deferredResult 保存到内存行列步队

return deferredResult;

}

// 在其他线程中...

deferredResult.setResult(data);

假如不懂得 Servlet 3 异步处置惩罚的细节,理解起来可能会必然的难度.

一个 ServletRequest 哀求可经由过程调用 request.startAsync() 措施设置为异步模式。此步骤最主要的感化是,在此 Servlet 和其他过滤器退出的环境下,response 依然可以维持打开状态,以便其他线程来完成处置惩罚。

调用 request.startAsync() 措施返回一个 AsyncContext。在异步处置惩罚中,AsyncContext 可以用来做进一步的节制。比如说,AsyncContext 供给的 dispatch 措施,可以在利用线程中调用,将哀求转发还 Servlet 容器。异步 dispatch(转发)类似于日常平凡应用的 forward 措施。不合的是,异步 dispatch(转发)是从利用里的一个线程转发到 Servlet 容器中的另一个线程,而 forward 措施则是在 Servlet 容器里的同一个线程间转发。

ServletRequest 可以定位当前的 DispatcherType(转发类型),此功能可以用于判断 Servlet 或 Filter 是在原始哀求线程上处置惩罚哀求,照样在异步转发线程中处置惩罚。

记着以上事实之后,接着懂得一下异步哀求处置惩罚 Callable 的历程:(1) 节制器返回一个 Callable ,(2) Spring MVC 开始异步处置惩罚,将 Callable 提交给 TaskExecutor,TaskExecutor 在一个自力线程中处置惩罚,(3) DispatcherServlet 和所有过滤器退出哀求处置惩罚线程,不过维持 response 为打开状态,(4) Callable 孕育发生一个结果之后,Spring MVC 将这个哀求转发还 Servlet 容器,(5) 再次调用 DispatcherServlet,并从新处置惩罚 Callable 异步孕育发生的结果。(2),(3),(4) 的准确顺序在不合环境下可能有所不合,这个取决于并发线程的处置惩罚速率。

异步哀求处置惩罚 DeferredResult 的事故顺序大年夜体上和处置惩罚 Callable 的顺序相同。不合的是,这里是由利用法度榜样的某些线程来处置惩罚异步结果:(1) 节制器返回一个 DeferredResult 工具,并将其保存到可造访的内存行列步队或列表中,(2) Spring MVC 开始异步处置惩罚,(3) DispatcherServlet 和所有过滤器退出哀求处置惩罚线程,不过维持 response 为打开状态,(4) 利用法度榜样在某些线程中设置 DeferredResult,之后 Spring MVC 将这个哀求转发还 Servlet 容器,(5) 再次调用 DispatcherServlet,并从新处置惩罚异步孕育发生的结果。

当节制器返回的 Callable 在履行时反生了非常,会呈现什么环境?这种环境类似于节制器发生非常时的环境。所呈现的非常会由同一节制器里的 @ExceptionHandler 措施处置惩罚,或由所设置设置设备摆设摆设的 HandlerExceptionResolver 实例来处置惩罚。假如是履行 DeferredResult 时呈现非常,你可以选择调用 DeferredResult 供给的 setErrorResult(Object) 措施,该措施须供给一个非常或其他你设置设置的工具。 当结果是一个 Exception 时,会由同一节制器里的 @ExceptionHandler 措施处置惩罚,或由所设置设置设备摆设摆设的 HandlerExceptionResolver 实例来处置惩罚。

16.4 Handler 映射

16.4.1 应用 HandlerInterceptor 拦截哀求

Spring 的 handler 映射机制包孕了 handler 拦截器。应用handler 拦截器,可以在某些的哀求中利用的特殊的功能,比如说,反省权限。

handler 映射的拦截器必须实现 HandlerInterceptor 接口(此节接口位于 org.springframework .web.servlet 包中)。这个接口定义了三个措施:preHandle(..) 在 handler 履行前调用;postHandle(..) 在handler 履行后调用;afterCompletion(..) 在整一个哀求完成后调用。这三个措施基础足够应对各类预处置惩罚和后处置惩罚的状况。

preHandle(..) 措施返回一个 boolean 值。你可以应用这个措施来中断或继承处置惩罚 handler 履行链。当此措施返回 true 时,hadler 履行链会继承履行;反之,DispatcherServlet 会觉得此拦截器已处置惩罚完成该哀求(和衬着一个视图),之后不再履行余下的拦截器,也不在履行 handler 履行链。

可以应用 interceptors 属性设置设置设备摆设摆设拦截器。所有从 AbstractHandlerMapping 承袭过来的 HandlerMapping 类都拥有此属性。演示例子如下:

public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {

private int openingTime;

private int closingTime;

public void setOpeningTime(int openingTime) {

this.openingTime = openingTime;

}

public void setClosingTime(int closingTime) {

this.closingTime = closingTime;

}

public boolean preHandle(HttpServletRequest request, HttpServletResponse response,

Object handler) throws Exception {

Calendar cal = Calendar.getInstance();

int hour = cal.get(HOUR_OF_DAY);

if (openingTime

留意,HandlerInterceptor 的 postHandle 措施不必然适用于@ResponseBody和ResponseEntity措施。在这种环境下,HttpMessageConverter 实例会在 postHandle 措施履行之前就将数据写到 response 并提交 response,以是 postHandle 措施弗成能再处置惩罚 response(如添加一个 Header)。相反,利用法度榜样可以实现 ResponseBodyAdvice ,将其声明为 @ControllerAdvice bean 或将其直接在 RequestMappingHandlerAdapter 中设置设置设备摆设摆设它。

16.5 视图解析

所有 web 利用的 MVC 框架都邑提了视图解析的规划,Spring 供给的视图解析,可以让你在不指定特定视图技巧的条件下,便可在浏览器中衬着模型。Spring 支持应用 USP,Veloctiy 模板和 XSLT 视图技巧,这些视图技巧都是开箱即用的。查看Chapter 17, 视图技巧,可以懂得到若何集成和应用多种不合的视图技巧。

ViewResolver 和 View 是 Spring 处置惩罚视图的两个紧张接口。傍边,ViewResolver 供给了视图名称和真实视图之间的映射,View 则是认真办理某个视图的技巧的哀求预处置惩罚和哀求的后续处置惩罚。

16.5.1 应用 ViewResolver 接口解析视图

Spring web MVC 中的所有 handler 措施都必要解析某一个逻辑视图名称,可所以显式的,如如返回 String, View, 或 ModelAndView 实例,也可所以隐式的(这个需基于事先约定)。

举个例子,解析 JSP 视图技巧,可以应用 UrlBasedViewResolver 解析器。此解析器会将视图名称转换为 url,和通报哀求到 RequestDispatcher,以便衬着视图。

当返回 test 逻辑逻辑视图名时,此视图解析器会将哀求转发到 RequestDispatcher,接着 RequestDispatcher 将哀求发送到 /WEB-INF/jsp/test.jsp。

16.5.2 视图解析器链

Spring 供给多种视图技巧。是以,你可以定义解析器链,比如,可在某些环境下覆盖指定视图。可经由过程在利用高低文中添加多个解析器来定义解析器链,如有必要的,也可指定这些解析器的顺序。记着,order 属性越高,解析器的链上位置约靠后。

如下例子,定义了包孕两个解析器的解析器链。傍边一个是 InternalResourceViewResolver,此解析器老是自动定位到解析器链中着末一个;别的一个是 XmlViewResolver,用来指定 Excel 视图。InternalResourceViewResolver 不支持 Excel 视图。

假如一个视图解析器不能导出一个视图,Spring 会检索高低文,查找其他视图解析器。假如查找到其他视图解析器,Spring 会继承处置惩罚,直到有解析器导出一个视图。假如没有解析器返回一个视图,Spring 会抛出 ServletException。

视图解析协议规定视图解析器可以返回 null,表示没有找到指定的视图。然而,不是所有的视图解析器返回null,都表示没有找到视图。由于某些环境下,视图解析器也无法检测视图是否存在。比如,InternalResourceViewResolver 在内部逻辑里应用 RequestDispatcher,假如 JSP 文件存在,那分发是独一可以找到 JSP 文件的要领,可分发只能履行一次。VelocityViewResolver 和其他解析器也类似。

16.5.4 ContentNegotiatingViewResolver

ContentNegotiatingViewResolver 自身并没有去解析视图,而是将其委派给其他视图解析器,选择指定相应表述返回给客户端。有以下两种策略,容许客户端哀求指定表述要领的资本:

不合的资本应用不合的 URI 表示:平日应用文件拓展名来表示不合的相应表述,如 http://www.example.com/users/fred.pdf 哀求用户 fred 的 pdf 视图表述,http://www.example.com/users/fred.xml 则是哀求用户 fred 的 xml 视图表述。

应用相同的 uri 加载指定资本,不过应用 Accept HTTP 哀求头表示其哀求的http://en.wikipedia.org/wiki/Internet_media_type[媒体类型]。如uri http://www.example.com/users/fred,当 Accept 为 application/pdf ,表示哀求用户 fred 的pdf视图表述,当 Accept 为 application/xml 表示哀求用户 fred 的xml 视图表述。这种策略也可称为 内容协商.

为了支持同一资本的多种表述,Spring 供给了 ContentNegotiatingViewResolver,可根据文件拓展名或 Accept 头字段值选择指定资本的表述.ContentNegotiatingViewResolver 自身并解释视图,而是将其转发给经由过程 ViewResolvers 属性设置设置设备摆设摆设的视图解析器.

如下,是一个 ContentNegotiatingViewResolver 设置设置设备摆设摆设样例:

InternalResourceViewResolver 处置惩罚试图名称的解析和 JSP 页面,别的,BeanNameViewResolver会返回基于 bean 名称的视图(可参考 "应用 ViewResolver 解析视图,懂得 Spring 若何探求和初始化一个视图")。在上述例子中,content bean 是一个承袭 AbstractAtomFeedView 的类,这个bean 可以返回一个 RSS 原子.

在上述设置设置设备摆设摆设中,当哀求是由 .html拓展名组成时,视图解析器会去探求一个匹配 text/html 的视图。InternalResourceViewResolver 供给了 text/html 的映射。当哀求是由 .atom 拓展名组成时,视图解析器会去探求一个匹配 .atom 的视图。这个视图 BeanNameViewResolver 有供给,若视图名称为 content,则映射到 SampleContentAtomView。当哀求是由 .json拓展名组成时,会选择 DefaultViews 供给的 MappingJackson2JsonView 接口,留意这个映射与视图名称无关。别的,客户真个哀求不带拓展名,经由过程 Accept 头字段指定媒体类型时,也会履行和文件拓展名一样的处置惩罚逻辑。

可以根据 http://localhost/content.atom 或 http://localhost/content和Accept字段值为 application/atom+xml 两种环境,返回原子视图的节制器代码如下:

@Controller

public class ContentController {

private List contentList = new ArrayList();

@RequestMapping(value="/content", method=RequestMethod.GET)

public ModelAndView getContent() {

ModelAndView mav = new ModelAndView();

mav.setViewName("content");

mav.addObject("sampleContentList", contentList);

return mav;

}

}

16.7 构建 URI

Spring MVC 供给了构建和编码 URI 的机制,这种机制的应用必要经由过程 UriComponentsBuilder 和 UriComponents.

UriComponents uriComponents = UriComponentsBuilder.fromUriString(

"http://example.com/hotels/{hotel}/bookings/{booking}").build();

URI uri = uriComponents.expand("42", "21").encode().toUri();

留意,UriComponents 是弗成变的;假如有必要的,expand() 和 encode() 操作会返回一个新的实例。你可以零丁应用一个 URI 原件展开和编码 URI 模版字符串:

UriComponents uriComponents = UriComponentsBuilder.newInstance()

.scheme("http").host("example.com").path("/hotels/{hotel}/bookings/{booking}").build()

.expand("42", "21")

.encode();

Servlet 情况中,ServletUriComponentsBuilder 的子类供给了从 Servlet 哀求复制 URL 信息的静态措施:

HttpServletRequest request = ...

// 重用 host, scheme, port, path 和 query

// 调换 "accountId" 查询参数

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromRequest(request)

.replaceQueryParam("accountId", "{id}").build()

.expand("123")

.encode();

16.10文件上传

16.10.1文件上传先容

Spring本身也是支持在web模块式应用文件上传的,假如你想应用Spring的文件上传模块的话,就必须要自己生命一个处置惩罚文件上传的MultipartResolver实现类,平日环境洗我们应用的是CommonsMultipartResolver。Spring会检测每一个Http哀求,检测哀求中是否包孕文件上传的内容,假如没有文件上传的内容被检测到的话,Spring会照常处置惩罚这个哀求,然则假如有上传内容被检测到的话,我们在Spring中声明的MultipartResolver就会爬上用处了,我们在上传文件时刻附加的参数,可以像正常参数一样被我们取到。

16.10.2通用的文件上传逻辑

当然,为了multipart resolver 能够正常运行,必要在类路径添加一些jar包. 对付 CommonsMultipartResolver 而言, 你必要应用 commons-fileupload.jar.

当 Spring DispatcherServlet 检测到一个 multi-part 哀求时, 就激活在高低订婚义的resolver 并移交哀求. 然后,resolver 包装当前 HttpServletRequest 成支持multipart文件上传的 MultipartHttpServletRequest. 经由过程 MultipartHttpServletRequest, 你可以获取当前哀求所包孕multiparts信息,实际上你也可以在controllers获取多个multipart文件.

16.10.4 在表单中处置惩罚一个上传文件

在完成添加 MultipartResolver 之后, 这个哀求就会和通俗哀求一样被处置惩罚. 首先, 创建一个带上传文件的表单. 设置( enctype="multipart/form-data") 奉告浏览器将表单编码成 multipart request:

Please upload a file

下一步是创建一个 controller 处置惩罚上传文件. 必要在哀求参数中应用 MultipartHttpServletRequest 或者 MultipartFile, 这个 controller 和 normal annotated @Controller异常相似:

@Controller

public class FileUploadController {

@RequestMapping(value = "/form", method = RequestMethod.POST)

public String handleFormUpload(@RequestParam("name") String name,

@RequestParam("file") MultipartFile file) {

if (!file.isEmpty()) {

byte[] bytes = file.getBytes();

// 将bytes保存

return "redirect:uploadSuccess";

}

return "redirect:uploadFailure";

}

}

留意 @RequestParam 将措施参数映射输入元素的声明形式. 在这个例子中, 对 byte[] 并没有做什么操作, 然则在实践中你可以保存在数据库, 存储在文件系统, 等等.

16.11 非常处置惩罚

16.11.1 非常处置惩罚

Spring的 HandlerExceptionResolver 用来处置惩罚包括controller履行时代在内的非常. 一个 HandlerExceptionResolver 有点类似于 web 利用中定义在 web.xml 中的非常映射. 然则,它们供给了加倍机动的要领.比如说,在抛出非常的时刻它供给了一些关于哪个非常处置惩罚器将被履行的信息.此外,在哀求被转发到别的一个URL之前,编程要领的非常处置惩罚供给了更多的处置惩罚要领.s

实现 HandlerExceptionResolver 接口的话, 只需实现 resolveException(Exception, Handler) 措施并且返回一个 ModelAndView, 也可以应用供给的 SimpleMappingExceptionResolver 或者创建一个 @ExceptionHandler 措施. SimpleMappingExceptionResolver 使你能够获取任何非常的类名,这些非常可以被抛出或者映射到一个视图. 这和Servlet API的非常映射特点是等价的,然则它可以经由过程不合的非常处置惩罚器实现更好的非常处置惩罚. 别的 @ExceptionHandler 可以被评释在一个处置惩罚非常的措施上. 这个措施可以被定义在包孕 @Controller 的类局部区域 或者定义在包孕 @ControllerAdvice 的类里面利用于多个 @Controller 类.

16.11.2 @ExceptionHandler

HandlerExceptionResolver 接口 和 SimpleMappingExceptionResolver

实现类容许映射非常到详细的视图,在转发到视图之前可以有Java逻辑代码. 然则, 有些环境下,

尤其是评释 @ResponseBody 的措施而不是一个视图的环境下,它可以更方便的直接设置返回的状态和返回的差错内容.就像我们可以在HandlerExceptionResolver接口实现中在呈现非常的环境下返回一个友好的提示页面,对付@ResponseBody这种环境的话我们可以处置惩罚成返回一个默认的code值来供前段识别或者返回一个默认的数值等等。

可以经由过程 @ExceptionHandler 措施. 当它在一个 controller 内部声明时,它将被用于那个controller(或它的子类)的 @RequestMapping 措施抛出的非常.

@Controller

public class SimpleController {

// @RequestMapping methods omitted ...

@ExceptionHandler(IOException.class)

public ResponseEntity handleIOException(IOException ex) {

// prepare responseEntity

return responseEntity;

}

}

@ExceptionHandler 的value可以设置一个必要被处置惩罚的非常数组. 假如一个非常被抛出并且包孕在这个非常列表中, 然后就会调用 @ExceptionHandler 措施. 假如没有设置value,

那么就会应用参数里面的非常.和标准controller的 @RequestMapping 措施很相似, @ExceptionHandler 措施的参数值和返回值相称机动. 比如说, HttpServletRequest 可以在 Servlet 情况中被接管, PortletRequest 在 Portlet 情况中被接管. 返回值可所以 String, 它将解释为一个视图, 可所以 ModelAndView 工具, 可所以 ResponseEntity 工具, 或者你可以添加 @ResponseBody 措施直接返回消息.

16.11.5 处置惩罚默认的差错页面

当响应的code是error状态然则response的相应体是空的时刻,容器平日必要衬着一个默认的差错页面供用户应用。为来定义这个通用的差错页面,你可以在web.Xml中声明标签,在Servlet3之前,你还必要为每个标签声明对应的error code,然则到来Servelt3之后你就不必要这么做了。

/error

@Controller

public class ErrorController {

@RequestMapping(value="/error", produces="application/json")

@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"));

return map;

}

}

Spring的机动设置设置设备摆设摆设信息

16.13.2 ModelAndView

ModelMap 类本色上是一个好听一点的 Map,它坚持一个通用的命名约定,把用于显示在 View 上面的工具添加到此中。斟酌下面的 Controller 实现;留意添加到 ModelAndView 中的工具没有指定随意率性关联的名称。

public class DisplayShoppingCartController implements Controller {

public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {

List cartItems = 奸淫;

User user = 奸淫;

ModelAndView mav = new ModelAndView("displayShoppingCart");

mav.addObject(cartItems);

mav.addObject(user);

return mav;

}

}

ModelAndView 类应用了一个 ModelMap 类,ModelMap 是一个自定义的 Map 实现,它会为添加到此中的工具自动天生一个 key。抉择被添加工签字称的策略是,假如是一个 scalar 工具,会应用工具类的简短类名。对付将 scalar 工具添加到 ModelMap 实例的环境,下面的例子展示了天生的名称:

添加的 x.y.User 实例会天生名称 user。

添加的 x.y.Registration 会天生名称 registration

添加的 x.y.Foo 实例会天生名称 foo

添加的 java.util.HashMap 实例会天生名称 hashMap。在这种环境下,你可能想要显式指定名称,由于 hashMap 不敷直不雅。

添加 null 会导致抛出一个 IllegalArgumentException。假如你要添加的一个工具(或多个工具)为 null,那么你也想要显式指定名称。

在添加一个 Set 或 List 之后,天生名称的策略是,应用聚拢中第一个工具的简短类名,并在名称后追加 List。对数组应用的也是该策略。下面的例子会让你对聚拢的名称天生的语义加倍清楚:

添加一个具有零个或多个 x.y.User 元素的 x.y.User[] 数组,会天生名称 userList。

添加一个具有零个或多个 x.y.User 元素的 x.y.Foo[] 数组,会天生名称 fooList。

添加一个具有零个或多个 x.y.User 元素的 java.util.ArrayList,会天生名称 userList。

添加一个具有零个或多个 x.y.Foo 元素的 java.util.HashSet,会天生名称 fooList。

根本不能添加一个空的 java.util.ArrayList(实际上,addObject(..) 调用基础上会是一个无效操作)。

您可能还会对下面的文章感兴趣: