Spring 为展现层提供的基于 MVC设计理念的优秀的Web 框架,是目前最主流的MVC 框架之一
Spring3.0 后全面超越 Struts2,成为最优秀的 MVC框架
Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口。
支持 REST 风格的 URL请求
采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性
Spring MVC 使用 @RequestMapping 注解为控制器指定可以处理哪些 URL 请求 ()
在控制器的类定义及方法定义处都可标注
DispatcherServlet 截获请求后,就通过控制器上@RequestMapping 提供的映射信息确定请求所对应的处理方法。
示例:
@Controller
public class Helloworld {
@RequestMapping("/helloworld")
public String hello() {
System.out.println("hello");
return "success";
}
}
@RequestMapping 除了可以使用请求 URL 映射请求外,还可以使用请求方法、请求参数及请求头映射请求
@RequestMapping 的 value、method、params 及 heads 分别表示请求 URL、请求方法、请求参数及请求头的映射条件,他们之间是与的关系,联合使用多个条件可让请求映射更加精确化。
params 和 headers支持简单的表达式:
示例:
Ant 风格资源地址支持 3 种匹配符:
@RequestMapping 还支持 Ant 风格的 URL:
/user/*/createUser: 匹配
/user/aaa/createUser、/user/bbb/createUser 等 URL
/user//createUser: 匹配
/user/createUser、/user/aaa/bbb/createUser 等 URL
/user/createUser??: 匹配
/user/createUseraa、/user/createUserbb 等 URL
带占位符的 URL 是 Spring3.0 新增的功能,该功能在SpringMVC 向 REST 目标挺进发展过程中具有里程碑的意义
通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过 @PathVariable(“xxx”) 绑定到操作方法的入参中。
REST: 即 Representational State Transfer。(资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用
资源(Resources): 网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要 获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识 别符。
表现层(Representation): 把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格 式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“ 状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是 “ 表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动 词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
示例:
HiddenHttpMethodFilter:浏览器 form 表单只支持 GET 与 POST 请求,而DELETE、PUT 等 method 并不支 持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT 与DELETE 请求。
请求头包含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中
@CookieValue 可让处理方法入参绑定某个 Cookie 值
Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。
级联属性:对象中的成员属性对象
哪些 ServletAPI 类型的参数
直接写在hander方法的参数部分即可
Spring MVC 提供了以下几种途径输出模型数据:
ModelAndView: 处理方法返回值类型为ModelAndView时, 方法体即可通过该对象添加模型数据
Map 及 Model: 入参为org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
@SessionAttributes: 将模型中的某个属性暂存到HttpSession 中,以便多个请求之间可以共享这个属性
@ModelAttribute: 方法入参标注该注解后, 入参的对象
就会放到数据模型中
控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息。
添加模型数据:
设置视图:
Springmvc无论hander返回的是什么类型,都会封装成ModelAndView
Spring MVC 在内部使用了一个org.springframework.ui.Model 接口存储模型数据
具体步骤
Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
目标方法可以添加Map类型(实际上也可以是Model类型或ModelMap类型)的参数。
如果方法的入参为 Map 或 Model 类 型,Spring MVC 会将隐含模型的引用传递给这些入参。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据
属性默认传递到request域里
还是使用Map传递属性
若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个 @SessionAttributes, Spring MVC 将在模型中对应的属性暂存到 HttpSession 中。(当然request域中的属性还在)
@SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(实际上使用的是value 属性值),还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中 (实际上使用的是types 属性值)
@SessionAttributes(types=User.class) 会将隐含模型中所有类型 为 User.class 的属性添加到会话中。
注意:该注解只能放在类的上面。 而不能修饰方法.
@ModelAttribute 的方法。
请求处理方法执行完成后,最终返回一个 ModelAndView对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个ModelAndView 对象,它包含了逻辑名和模型对象的视图
Spring MVC 借助视图解析器**(**ViewResolver)得到最终 的视图对象(View),最终的视图可以是 JSP ,也可能是Excel、JFreeChart 等各种表现形式的视图
对于最终究竟采取何种视图对象对模型数据进行渲染,s处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现 MVC 的充分解耦
一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理
如果返回的字符串中带 forward: 或 redirect: 前缀 时,SpringMVC 会对他们进行特殊处理:将 forward: 和redirect: 当成指示符,其后的字符串作为 URL 来处理
redirect:success.jsp:会完成一个到 success.jsp 的重定向的操作
forward:success.jsp:会完成一个到 success.jsp 的转发操作
通过 SpringMVC 的表单标签可以实现将模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显
页面的 URL 是相同的。只要满足该最佳条件的契约,
SpringMVC 提供了多个表单组件标签,如
form:input、form:password、form:hidden、form:textarea, 对应 HTML 表单的 text、password、hidden、textarea 标签
form:radiobutton:单选框组件标签,当表单 bean 对应的属性值和 value 值相等时,单选框被选中
form:radiobuttons:单选框组标签,用于构造多个单选框
form:checkbox:复选框组件。用于构造单个复选框
form:checkboxs:用于构造多个复选框。使用方式同form:radiobuttons 标签
form:select:用于构造下拉框组件。使用方式同form:radiobuttons 标签
form:option:下拉框选项组件标签。使用方式同form:radiobuttons 标签
form:errors:显示表单组件或数据校验所对应的错误
优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀
若将 DispatcherServlet 请求映射配置为 /,则 Spring MVC 将捕获WEB 容器的所有请求,包括静态资源的请求, SpringMVC 会将他们当成一个普通请求处理,因找不到对应处理器将导致错误。
可以在 SpringMVC 的配置文件中配置
一般 WEB 应用服务器默认的 Servlet 的名称都是 default。若所使用的WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定
Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象
DataBinder 调用装配在 Spring MVC 上下文中的ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中
调用 Validator 组件对已经绑定了请求消息的入参对象 进行数据合法性校验,并最终生成数据绑定结果BindingData 对象
Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参
java.lang.Boolean -> java.lang.String
java.lang.Character -> java.lang.Number
java.lang.Character -> java.lang.String
java.lang.Enum -> java.lang.String
java.lang.Number -> java.lang.Character
java.lang.Number -> java.lang.Number
java.lang.Number -> java.lang.String
java.lang.String -> java.lang.Boolean
java.lang.String -> java.lang.Character
java.lang.String -> java.lang.Enum
java.lang.String -> java.lang.Number
java.lang.String -> java.util.Locale
java.lang.String -> java.util.Properties
java.lang.String -> java.util.UUID
java.util.Locale -> java.lang.String
java.util.Properties -> java.lang.String
java.util.UUID -> java.lang.String
ConversionService 是 Spring 类型转换体系的核心接口。
可以利用 ConversionServiceFactoryBean 在 Spring 的 IOC 容器中定义一个 ConversionService. Spring 将自动识别出IOC 容器中的 ConversionService,并在 Bean 属性配置及Spring MVC 处理方法入参绑定等场合使用它进行数据的转换
可通过 ConversionServiceFactoryBean 的 converters 属性注册自定义的类型转换器
Spring 定义了 3 种类型的转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到ConversionServiceFactroyBean 中:
Converter(一般用这种):将 S 类型对象转为 T 类型对象
ConverterFactory:将相同系列多个 “同质” Converter 封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将 String 转换为 Number 及 Number 子类 (Integer、Long、Double 等)对象)可使用该转换器工厂类
GenericConverter:会根据源类对象及目标类对象所在的宿主类 中的上下文信息进行类型转换
ExceptionHandlerExceptionResolver 三个bean。
由 @InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定
@InitBinder方法不能有返回值,它必须声明为void。
@InitBinder方法的参数通常是是 WebDataBinder
对属性对象的输入/输出进行格式化,从其本质上讲依然属于 “类型转换” 的范畴。
Spring 在格式化模块中定义了一个实现ConversionService 接口的FormattingConversionService 实现类,该实现类扩展 了 GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能
FormattingConversionService 拥有一个FormattingConversionServiceFactroyBean 工厂类,后者用于在 Spring 上下文中构造前者
FormattingConversionServiceFactroyBean 内部已经注册了 :
NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性使用 @NumberFormat 注解
JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性使用 @DateTimeFormat 注解
装配了 FormattingConversionServiceFactroyBean 后,就可以在 Spring MVC 入参绑定及模型数据输出时使用注解驱动了。
JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 中 .
JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证
Spring 4.0 拥有自己独立的数据校验框架,同时支持 JSR 303 标准的校验框架。
Spring 在进行数据绑定时,可同时调用校验框架完成数据校验工作。在 Spring MVC 中,可直接通过注解驱动的方式进行数据校验
Spring 的 LocalValidatorFactroyBean 既实现了 Spring 的Validator 接口,也实现了 JSR 303 的 Validator 接口。只要在 Spring 容器中定义了一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的 Bean 中。
Spring 本身并没有提供 JSR303 的实现,所以必须将JSR303 的实现者的 jar 包放到类路径下。
在已经标注了 JSR303 注解的表单/命令对象前标注一个@Valid,Spring MVC 框架在将请求参数绑定到该入参对象后,就会调用校验框架根据注解声明的校验规则实施校验
Spring MVC 是通过对处理方法签名的规约来保存校验结果的:前一个表单/命令对象的校验结果保存到随后的入参中,这个保存校验结果的入参必须是 BindingResult 或Errors 类型,这两个类都位于org.springframework.validation 包中
在表单/命令对象类的属性中标注校验注解,在处理方法对 应的入参前添加 @Valid,Spring MVC 就会实施校验并将校验结果保存在被校验入参对象之后的 BindingResult 或Errors 入参中。
常用方法:
每个属性在数据绑定和数据校验发生错误时,都会生成一个对应的 FieldError 对象。
当一个属性校验失败后,校验框架会为该属性生成 4 个消息代码,这些代码以校验注解类名为前缀,结合modleAttribute、属性名及属性类型名生成多个对应的消息代码:例如 User 类中的 password 属性标准了一个 @Pattern 注解,当该属性值不满足 @Pattern 所定义的规则时, 就会产生以下 4 个错误代码:
当使用 Spring MVC 标签显示错误消息时, Spring MVC 会查看WEB 上下文是否装配了对应的国际化消息,如果没有,则显示默认的错误消息,否则使用国际化消息。
若数据类型转换或数据格式转换时发生错误,或该有的参数不存在,或调用处理方法时发生错误,都会在隐含模型中创建错误消息。其错误代码前缀说明如下:
注册国际化资源文件
编写目标方法,使其返回 JSON 对应的对象或集合
在方法上添加 @ResponseBody 注解
HttpMessageConverter 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息
HttpMessageConverter接口定义的方法:
使用 HttpMessageConverter
当控制器处理方法使用到 @RequestBody/@ResponseBody 或HttpEntity/ResponseEntity 时, Spring 首先根据请求头或响应头的Accept 属性选择匹配的 HttpMessageConverter, 进而根据参数类型或泛型类型的过滤得到匹配的 HttpMessageConverter, 若找不到可用的HttpMessageConverter 将报错
@RequestBody 和 @ResponseBody 不需要成对出现
默认情况下,SpringMVC 根据 Accept-Language 参数判断客户端的本地化类型。
当接受到请求时,SpringMVC 会在上下文中查找一个本地化解析器(LocalResolver),找到后使用它获取请求 所对应的本地化类型信息。
SpringMVC 还允许装配一个动态更改本地化类型的拦截器,这样通过指定一个请求参数就可以控制单个请求的本地化类型。
AcceptHeaderLocaleResolver:根据 HTTP 请求头的Accept-Language 参数确定本地化类型,如果没有显式定义本地化解析器, SpringMVC 使用该解析器。
CookieLocaleResolver:根据指定的 Cookie 值确定本地化类型
SessionLocaleResolver:根据 Session 中特定的属性确定本地化类型
LocaleChangeInterceptor:从请求参数中获取本次请求对应的本地化类型。
Spring MVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。Spring 用Jakarta Commons FileUpload 技术实现了一个MultipartResolver 实现类:CommonsMultipartResovler
Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需现在上下文中配置 MultipartResolver
defaultEncoding: 必须和用户 JSP 的 pageEncoding 属性一致,以便正确解析表单的内容
为了让 CommonsMultipartResovler 正确工作,必须先 将 Jakarta Commons FileUpload 及 Jakarta Commons io的类包添加到类路径下。
如果有一个拦截器的preHandle返回的是true,则一定会执行这个拦截器的afterCompletion释放资源
Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。
SpringMVC 提供的 HandlerExceptionResolver 的实现类
主要处理 Handler 中用 @ExceptionHandler 注解定义的方法。
@ExceptionHandler 注解定义的方法优先级问题:例如发生的是NullPointerException,但是声明的异常有RuntimeException 和 Exception,此候会根据异常的最近继承关系找到继承深度最浅的那个 @ExceptionHandler注解方法,即标记了 RuntimeException 的方法
ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话,会找 @ControllerAdvice 中的 @ExceptionHandler 注解方法
在@ExceptionHandler方法的入参中可以加入Exception类型的参数,该参数即对应发生的异常对象
@ExceptionHandler方法的入参中不能传入Map.若希望把异常信息传导页面上,需要使用ModelAndView作为返回值
@ExceptionHandler方法标记的异常有优先级的问题.(越具体越优先)
@ControllerAdvice: 如果在当前Handler中找不到@ExceptionHandler方法来出来当前方法出现的异常,则将去@ControllerAdvice标记的类中查找@ExceptionHandler标记的方法来处理异常.
在异常及异常父类中找到 @ResponseStatus 注解,然后使用这个注解的属性进行处理。
定义一个 @ResponseStatus 注解修饰的异常类