1.SpringMVC概述
SpringMVC是基于MVC设计理念的优秀的WEB框架,是目前最主流的MVC框架之一。
Spring3.0后的SpringMVC框架在很多地方都已经超越了Struts2框架,成为最优秀的MVC框架
SpringMVC通过一套MVC注解,让pojo成为了处理请求的控制器,无须实现任何的接口。
支持REST风格的URL请求。
采用了松散耦合可插拔组件结构,比其它MVC框架更具有扩展性和灵活性。
2.HelloWorld
步骤:
1)加入jar包
2)在web.xml配置前端处理器DispatcherServlet
3)加入SpringMVC配置文件
4)编写业务逻辑处理器,用注释标识
5)编写视图
配置前端处理器:
配置DispatcherServlet:DispatcherServlet默认加载/WEB-INF/<servletName-servlet>.xml的Spring配置文件,启动WEB层的Spring容器。也可以通过contextConfigLocation初始化参数自定义配置文件的位置和名称。
配置自动扫描的包
<context:component-scanbase-package=”com.huawei.springmvc”></context:component-scan>
配置视图解析器:
视图名称解析器:将视图逻辑名解析为:/WEB-INF/pages/<viewName>.jsp
3.使用@RequestMapping映射请求
SpringMVC 使用@RequestMapping注解为控制器指定可以处理哪些前台请求。
在控制器的类定义及方法定义处都可以标注
@RequestMapping
-类定义处:提供初步的请求映射信息。相对于WEB 应用的根目录。
-方法处:提供进一步的细分映射信息。相对于类定义处的URL。若类定义处未标注@RequestMapping,则方法处标记的URL相对于WEB应用的根目录。
DispatcherServlet截获请求后,就通过控制器上@RequestMapping提供的映射信息确定请求所对应的处理方法。
3.1 映射请求参数、请求方法或请求头
@RequestMapping除了可以使用使用请求URL映射请求外,还可以使用请求方法、请求参数及请求头映射请求。
@RequestMapping的value、method、params及heads分别表示请求URL、请求方法、请求参数及请求头的映射条件,他们之间是与的关系,联合使用多个条件可以让请求映射更加的精确化。
params和headers支持简单的表达式:
param1:表示请求必须包含名为param1的请求参数。
!param1:表示请求不能包含名为param1的请求参数。
Param1 != value1:表示请求包含名为param1的请求参数,但其值不能为value1.
{“param1=value1”, “param2”}:请求必须包含名为param1和param2的两个请求参数,且param1参数的值必须为value
SpringMVC与Sturts2 action映射的比较
1. SpringMVC 可以通过请求报文中的所有内容与action方法做映射
2. Struts2只能通过请求中的URL与ACTION做映射
3.2 使用@RequestMapping映射请求
l Ant风格资源地址支持3种匹配符:
1. ? : 匹配文件名中的一个字符
2. *: 匹配文件名中的任意字符
3. **: 匹配多层路径
l @RequestMapping还支持Ant风格的URL
/user/*/createUser:匹配
/user/abc/createUser /user/aaa/createUser等等
/user/**/createUser:匹配
/user/createUser /user/abc/cda/createUser等等
/user/createUser??:匹配
/user/createUseraa /user/createUserbb 等等
3.3 使用@PathVariable映射URL绑定的占位符
l 带占位符的URL是spring3.0新增的功能,该功能在SpringMVC向REST目标挺进发过过程中具有里程碑的意义。
l 通过@PathVariable可以将URL中占位符参数绑定到控制器处理方法的入参中:URL中的{***}占位符可以通过@PathVariable(“***”)绑定到操作方法的入参中。
4.REST
l REST: 即RepresentationalState Transfer. (资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正在得到越来越多的网站的采用。
l 资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定URI。要获取这个资源,访问它的URI就可以,因此URI即为每一个资源的独一无二的识别符。
l 表现层(Representation): 把资源具体呈现出来的形式。叫做它表现层(Representation)。比如,文件可以用txt格式表现,也可以用HTML格式,xml格式,JSON格式表现,甚至可以采用二进行格式。
l 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。Http协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户想要操作服务器,必须通过某种手段,让服务器发生状态的转化(State Transfer).而这种转化是建立在表现层之上的,所以就是”表现层状态转化”。具体说就是HTTP协议里面四个表示操作方式的动词。GET POST PUT DELETE
1)GET用来获取资源
2)POST用来新建资源
3)PUT用来更新资源
4)DELETE用来删除资源
例子:
/order/1 HTTP GET : 得到id为1的订单
/order/1 HTTP DELETE: 删除id为1的订单
/order/1 HTTP PUT: 更新id为1的订单
/order HTTP POST: 新增order
HiddenHttpMethodFilter:浏览器form表单只支持GET,POST请求,而DELETE,PUT等method并不支持,Spring3.0添加一个过滤器,可以将这些请求转换为标准的http方法,使和支持GET, POST,PUT与DELETE请求。
5.请求处理方法签名
l SpringMVC通过分析处理方法的签名,将HTTP请求信息绑定到处理方法的相应入参中。
l SpringMVC对控制器处理方法签名的限制是很宽松的,几乎可以按喜欢的任何方法对方法进行签名。
l 必要时可以对方法及方法标注相应的注解@PathVariable、@RequestParam、@RequestHeader等等),SpringMVC框架会将HTTP请求的信息绑定到相应的方法入参中,并根据方法的返回值类型做出相应的后续处理。
5.1使用@RequestParam绑定请求参数值
在处理方法入参处使用@RequestParam可以把请求参数传递给请求方法
Value: 参数名
Required: 是否必须。默认为true,表示请求参数中必须包含对应的参数,若不存在将抛出异常。
5.2 使用@RequestHeader绑定请求报头的属性值
请求头包含了若干属性,服务器可以据此获知客户端的信息,通过@RequestHeader即可将请求头中的属性值绑定到处理方法的入参中。
5.3 使用@CookieValue绑定请求中的Cookie值
@CookieValue可以让处理方法入参绑定某个Cookie值
5.3 使用POJO对象绑定请求参数值
SpringMVC会按请求参数名和POJO属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。
例如: dept.deptid dept.address.tel等等
5.3 MVC的控制器方法可以接受哪些参数?
l HttpServletRequest
l HttpServletResponse
l HttpSession
l Java.security.Principal
l Locale
l InputStream
l OutputStream
l Reader
l Writer
6.模型绑定
SpringMVC提供了一个implicitModel隐含数据模型对象的概念,有点类似于Struts2中的ActionContext数据中心,它的类图如下:
SpringMVC提供了如下几种方式来操作模型数据:
l ModelAndView:处理方法返回值类型为ModelAndView时,方法体即可通过该对象添加模型数据。
l Map及Model作为处理方法的入参
l @SessionAttributes:将模型中的某个属性暂存到HttpSession中,以便多个请求之间可以共享这个属性。
l @ModelAttribute: 方法入参标注该注解后,入参对象就会放到数据模型中
6.1 ModelAndView
控制器处理方法的返回值如果为ModelAndView,则其既包含视图信息,也包含模型数据信息。
添加模型数据:
ModelAndViewaddObject(String attributeName, Object attributeValue)
ModelAndViewaddAllObject(Map<String, ?> modelMap)
设置视图:
VoidsetView(View view)
VoidsetViewName(String viewName)
6.2 Map及Model
SpringMVC在内部使用一个org.springframework.ui.Model接口存储模型数据
具体步骤:
1. SpringMVC在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
2. 如果方法的入参为Map或Model类型,SpringMVC会将隐含模型的引用传递给这些入参,在方法体内中,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据。
6.2 @SessionAttributes
若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个@SessionAttributes,SpringMVC将在模型中对应的属性暂存到HttpSession中。
@SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型需要放到会话中。
例如:
l @SessionAttributes(types=User.class)将会隐含模型中所有类型为User.class的属性添加到会话中。
l @SessionAttributes(value={“user1”,”user2”});
l @SessionAttributes(types={User.class, Dept.class})
l @SessionAttributes(value={“user1”, “user2”}, types={Dept.class})
6.2 @ModelAttribute
在方法定义上使用@ModelAttribute注解:SpringMVC在调用目标处理方法前,会先逐个调用在方法级上标注了@ModelAttribute的方法。
在方法的入参前使用@ModelAttribute注解:
1)可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数绑定到对象中,再传入入参。
2)将方法入参对象添加到模型中。
7. SpringMVC视图解析
7.1 视图与视图解析器
请求处理方法执行完成后,最终返回一个ModelAndView对象。对于那些返回Spring, View或ModelMap等类型的处理方法,SpringMVC也会在内部将它们装配成一个ModelAndView对象,它包含了逻辑名和模型对象的视图
SpringMVC借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是JSP,也可能是Excel,JFreeChart等各种表现形式的视图。
对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现MVC的完全解耦。
7.2 视图
视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户。
为了实现视图模型和具体实现技术的解耦,Spring在org.springframework.web.servlet包中定义了一个高度抽象的View接口
视图对象由视图解析器负责实例化。由于视图是无状态的,所以它们不会有线程安全问题。
7.3 常见的视图实现类
7.4 视图解析器
SpringMVC为逻辑视图名的解析提供了不同的策略,可以在SpringWEB上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器的实现类。
视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象。
所有的视图解析器都必须实现ViewResolver接口。
7.5 常见的视图解析器的实现类
我们可以选择一种视图解析器或混用多种视图解析器
每一个视图解析器都实现了Ordered接口并开放出一个order属性,可以通过order属性指定解析器的优先顺序,order越小优先级别越高。
Springmvc会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则将抛出ServletException异常。
7.6 InternalResourceViewResolver
JSP是最常见的视图技术,可以使用InternalResourceViewResolver作为视图解析器:
|
若项目中使用了JSTL,则SpringMVC会自动把视图由InternalResourceViewResolver转为JstlView
若使用JSTL的fmt标签则需要在SpringMVC的配置文件中配置国际化资源文件。
|
若希望直接响应通过SpringMVC渲染的页面,可以使用mvc:view-controller标签实现
<mvc:view-controllerpath="/success" view-name="success"/>
8. SpringMVC的重定向
l 一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理。
l 如果返回的字符串中带forward:或redirect:前缀时,SpringMVC会对他们进行特殊处理,将forward:和redirect:当成指示符,其后的字符串作为URL来处理。
9. 处理静态资源
l 若将DispatcherServlet请求映射配置为/,则SpringMVC将捕获WEB容器的所有请求,包括静态资源的请求,SpringMVC会将他们当成一个普通请求处理,因将不到对应处理器将导致错误。
l 可以在SpringMVC的配置文件中配置<mvc:default-servlet-handler/>的方式解决静态资源的问题:
n <mvc:default-servlet-handler/>将在SpringMVC上下文中定义一个DefaultServletHttpRequestHandler,它会对进入DispatcherServlet的语法进行筛查,如果发现是没有经过映射的请求,就将该请求交由WEB应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。
n 一般WEB应用服务器默认的Servlet的名称都是default.若所使用的WEB服务器的默认Servlet名称不是default,则需要通过default-servlet-name属性显示指定。
10.数据绑定程序
Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象
DataBinder 调用装配在 Spring MVC 上下文中的ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中
调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果BindingData 对象
Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参Spring MVC 通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。数据绑定的核心部件是DataBinder,运行机制如下:
11.自定义类型转换器
1.ConversionService是 Spring 类型转换体系的核心接口。
2.可以利用ConversionServiceFactoryBean 在 Spring 的 IOC容器中定义一个 ConversionService. Spring 将自动识别出IOC 容器中的ConversionService,并在 Bean 属性配置及Spring MVC 处理方法入参绑定等场合使用它进行数据的转换
3.可通过ConversionServiceFactoryBean 的 converters 属性注册自定义的类型转换器
|
11.1 Spring 支持的转换器
Spring 定义了 3 种类型的转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到ConversionServiceFactroyBean 中:
l Converter<S,T>:将 S 类型对象转为 T 类型对象
l ConverterFactory:将相同系列多个 “同质” Converter 封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将 String 转换为 Number 及 Number 子类(Integer、Long、Double 等)对象)可使用该转换器工厂类
l GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换
<mvc:annotation-drivenconversion-service=“conversionService”/>会将自定义的ConversionService 注册到Spring MVC 的上下文中
|
12.关于mvc:annotation-driven
<mvc:annotation-driven/> 会自动注册
1.RequestMappingHandlerMapping
2.RequestMappingHandlerAdapter
3.ExceptionHandlerExceptionResolver还将提供以下支持
支持使用ConversionService 实例对表单参数进行类型转换
支持使用@NumberFormat annotation、@DateTimeFormat
注解完成数据类型的格式化
支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证
支持使用@RequestBody 和 @ResponseBody 注解
13.@InitBinder
由 @InitBinder标识的方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定.
@InitBinder方法不能有返回值,它必须声明为void。
@InitBinder方法的参数通常是是WebDataBinder
14.数据格式化
对属性对象的输入/输出进行格式化,从其本质上讲依然属于 “类型转换”的范畴。
• Spring 在格式化模块中定义了一个实现ConversionService 接口的FormattingConversionService 实现类,该实现类扩展
了 GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能
• FormattingConversionService 拥有一个FormattingConversionServiceFactroyBean 工厂类,后者用于在 Spring 上下文中构造前者。
FormattingConversionServiceFactroyBean内部已经注册了 :
– NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性
使用 @NumberFormat 注解
– JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型
的属性使用 @DateTimeFormat 注解
• 装配了 FormattingConversionServiceFactroyBean 后,就可以在 SpringMVC 入参绑定及模型数据输出时使用注解驱动了。
<mvc:annotation-driven/> 默认创建的
ConversionService 实例即为FormattingConversionServiceFactroyBean
14.1 日期格式化
@DateTimeFormat 注解可对
java.util.Date、java.util.Calendar、java.long.Long 时间
类型进行标注:– pattern 属性:类型为字符串。指定解析/格式化字段数据的模式,
如:”yyyy-MM-dd hh:mm:ss”
– iso 属性:类型为 DateTimeFormat.ISO。指定解析/格式化字段数据
的ISO模式,包括四种:1. ISO.NONE(不使用) -- 默认
2. ISO.DATE(yyyy-MM-dd)
3. ISO.TIME(hh:mm:ss.SSSZ)
4. ISO.DATE_TIME(yyyy-MM-ddhh:mm:ss.SSSZ)
14.2 数值格式化
@NumberFormat 可对类似数字类型的属性进行标
注,它拥有两个互斥的属性:– style:类型为 NumberFormat.Style。用于指定样式类型,包括三种:
Style.NUMBER(正常数字类型)
Style.CURRENCY(货币类型)Style.PERCENT(百分数类型)
– pattern:类型为 String,自定义样式,如patter="#,###";
14.3 服务端数据校验
JSR 303 – Bean Validation 是一个数据验证的规范,2009年 11 月确定最终方案。2009 年 12 月 Java EE 6 发布,Bean Validation 作为一个重要特性被包含其中。本文将对 Bean Validation 的主要功能进行介绍,并通过一些示例来演示如何在 Java 开发过程正确的使用 Bean Validation。
Spring 4.0 拥有自己独立的数据校验框架,同时支持JSR303 标准的校验框架。
• Spring 在进行数据绑定时,可同时调用校验框架完成数据校验工作。在 Spring MVC 中,可直接通过注解驱动的方式进行数据校验
• Spring 的 LocalValidatorFactroyBean 既实现了 Spring 的Validator 接口,也实现了 JSR303 的 Validator 接口。只要在 Spring 容器中定义了一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的 Bean 中。
• Spring 本身并没有提供 JSR303 的实现,所以必须将JSR303 的实现者的 jar 包放到类路径下。<mvc:annotation-driven/> 会默认装配好一个LocalValidatorFactoryBean,通过在处理方法的入参上标注 @valid 注解即可让 Spring MVC 在完成数据绑定后执行数据校验的工作
• 在已经标注了 JSR303 注解的表单/命令对象前标注一个@Valid,Spring MVC 框架在将请求参数绑定到该入参对象后,就会调用校验框架根据注解声明的校验规则实施校验
• Spring MVC 是通过对处理方法签名的规约来保存校验结果的:前一个表单/命令对象的校验结果保存到随后的入参中,这个保存校验结果的入参必须是BindingResult 或Errors 类型,这两个类都位于org.springframework.validation 包中
需校验的 Bean 对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参
• Errors 接口提供了获取错误信息的方法,如 getErrorCount() 或getFieldErrors(String field)
• BindingResult 扩展了 Errors 接口
14.3.1 在目标方法中获取校验结果
在表单/命令对象类的属性中标注校验注解,在处理方法对应的入参前添加 @Valid,Spring MVC 就会实施校验并将校验结果保存在被校验入参对象之后的 BindingResult 或Errors 入参中。
• 常用方法:– FieldError getFieldError(String field)
– List<FieldError> getFieldErrors()
– Object getFieldValue(String field)
– Int getErrorCount()
14.3.2 在页面上显示错误
Spring MVC 除了会将表单/命令对象的校验结果保存到对应的 BindingResult 或 Errors 对象中外,还会将所有校验结果保存到 “隐含模型”
• 即使处理方法的签名中没有对应于表单/命令对象的结果入参,校验结果也会保存在 “隐含对象” 中。
• 隐含模型中的所有数据最终将通过 HttpServletRequest 的属性列表暴露给 JSP 视图对象,因此在 JSP 中可以获取错误信息
• 在 JSP 页面上可通过 <form:errors path=“userName”>显示错误消息
15.SpringMVC处理JSON
1. 加入 jar 包:
2. 编写目标方法,使其返回 JSON 对应的对象或集合
3. 在方法上添加 @ResponseBody 注解@RequestBody要放在目标方法的参数上,作用是把json字符串对象转成目标参数类型的对象
@ResponseBody要放在目标方法上,作用是把目标方法的返回值(java对象)转成json字符返回给浏览器
@ResponseBody @RequestMapping(value="ajax2") public AjaxUser ajax2(@RequestBody AjaxUser user)throws IOException{ user.setT_age(1111111); user.setT_name("zxxxxx"); return user; }
$('#submitBtn2').click(function(){ //收集页面数据 var obj = {'t_name':$('#name2').val(), 't_age':$('#age2').val(), 'brithDate':$('#brithDate2').val()}; //发送ajax请求 $.ajax({ url:'${pageContext.request.contextPath}/ajax2.do', data: JSON.stringify(obj), contentType:'application/json', type:'post', success:function(msg){ alert(msg); } }); });
16.消息转换器HttpMessageConverter
HttpMessageConverter<T>接口定义的方法:
– Boolean canRead(Class<?> clazz,MediaType mediaType): 指定转换器可以读取的对象类型,即转换器是否可将请求信息转换为 clazz 类型的对象,同时指定支持 MIME 类型(text/html,applaiction/json等)
– Boolean canWrite(Class<?> clazz,MediaType mediaType):指定转换器是否可将clazz 类型的对象写到响应流中,响应流支持的媒体类型在MediaType 中定义。
– LIst<MediaType> getSupportMediaTypes():该转换器支持的媒体类型。
– T read(Class<? extends T> clazz,HttpInputMessage inputMessage):将请求信息流转换为 T 类型的对象。
– void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage):将T类型的对象写到响应流中,同时指定相应的媒体类型为 contentType
系统内置消息转换器DispatcherServlet 默认装配RequestMappingHandlerAdapter,而RequestMappingHandlerAdapter 默认装配如下
HttpMessageConverter:
使用消息转换器的注意事项:
使用HttpMessageConverter<T> 将请求信息转化并绑定到处理方法的入参中或将响应结果转为对应类型的响应信息,Spring 提供了两种途径:
– 使用 @RequestBody / @ResponseBody 对处理方法进行标注
– 使用 HttpEntity<T> / ResponseEntity<T> 作为处理方法的入参或返回值
• 当控制器处理方法使用到@RequestBody/@ResponseBody 或
HttpEntity<T>/ResponseEntity<T> 时, Spring 首先根据请求头或响应头的Accept属性选择匹配的 HttpMessageConverter, 进而根据参数类型或泛型类型的过滤得到匹配的HttpMessageConverter, 若找不到可用的HttpMessageConverter 将报错
• @RequestBody 和 @ResponseBody 不需要成对出现
17.SpringMVC文件上传功能
17.1 配置上传功能
配置文件:
<!-- 配置MultipartResolver用于文件上传使用spring的CommosMultipartResolver--> <bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver" p:defaultEncoding="UTF-8" p:maxUploadSize="5400000" p:uploadTempDir="fileUpload/temp" > </ bean>
其中属性详解:
defaultEncoding="UTF-8" 是请求的编码格式,默认为iso-8859-1
maxUploadSize="5400000" 是上传文件的大小,单位为字节
uploadTempDir="fileUpload/temp" 为上传文件的临时路径
17.2 创建上传表单
<body> <h2>文件上传实例</h2> <formaction="fileUpload.html" method="post"enctype="multipart/form-data"> 选择文件:<inputtype="file" name="file"> <input type="submit"value="提交"> </form> </body>
17.3 编写上传控制类
1、使用SpringMVC注解RequestParam来指定表单中的file参数;
2、指定一个用于保存文件的web项目路径
3、通过MultipartFile的transferTo(Filedest)这个方法来转存文件到指定的路径。
//通过Spring的autowired注解获取spring默认配置的request @Autowired privateHttpServletRequest request; /*** * 上传文件 用@RequestParam注解来指定表单上的file为MultipartFile */ @RequestMapping("fileUpload") publicString fileUpload(@RequestParam("file") MultipartFile file) { //判断文件是否为空 if(!file.isEmpty()) { try{ //文件保存路径 StringfilePath = request.getSession().getServletContext().getRealPath("/")+ "upload/" +file.getOriginalFilename(); // 转存文件 file.transferTo(newFile(filePath)); }catch (Exception e) { e.printStackTrace(); } } //重定向 return"redirect:/list.html"; } /*** * 读取上传文件中得所有文件并返回 * * @return */ @RequestMapping("list") publicModelAndView list() { StringfilePath = request.getSession().getServletContext().getRealPath("/")+ "upload/"; ModelAndViewmav = new ModelAndView("list"); FileuploadDest = new File(filePath); String[]fileNames = uploadDest.list(); for(int i = 0; i < fileNames.length; i++) { //打印出文件名 System.out.println(fileNames[i]); } returnmav; }
17.4 MultipartFile类常用的一些方法
String getContentType():获取文件MIME类型
InputStream getInputStream():后去文件流
String getName() :获取表单中文件组件的名字
String getOriginalFilename() :获取上传文件的原名
long getSize() :获取文件的字节大小,单位byte
boolean isEmpty() :是否为空
void transferTo(File dest) :保存到一个目标文件中
17.5 多文件上传
多文件上传其实很简单,和上传其他相同的参数如checkbox一样,表单中使用相同的名称,然后action中将MultipartFile参数类定义为数组就可以。
接下来实现:
1.创建一个上传多文件表单:<body> <h2>上传多个文件实例</h2> <formaction="filesUpload.html" method="post" enctype="multipart/form-data"> <p> 选择文件:<inputtype="file" name="files"> <p> 选择文件:<inputtype="file" name="files"> <p> 选择文件:<inputtype="file" name="files"> <p> <inputtype="submit" value="提交"> </form> </body>
2、编写处理表单的action,将原来保存文件的方法单独写一个方法出来方便共用:
/*** * 保存文件 */ private boolean saveFile(MultipartFilefile) { // 判断文件是否为空 if (!file.isEmpty()) { try { // 文件保存路径 StringfilePath = request.getSession().getServletContext().getRealPath("/")+ "upload/" +file.getOriginalFilename(); // 转存文件 file.transferTo(newFile(filePath)); returntrue; } catch (Exceptione) { e.printStackTrace(); } } return false; }
3、编写action:
@RequestMapping("filesUpload") public StringfilesUpload(@RequestParam("files") MultipartFile[] files) { //判断file数组不能为空并且长度大于0 if(files!=null&&files.length>0){ //循环获取file数组中得文件 for(inti = 0;i<files.length;i++){ MultipartFilefile = files[i]; //保存文件 saveFile(file); } } // 重定向 return"redirect:/list.html"; }
18. 自定义拦截器
18.1 定义拦截器的方法
SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式
l 第一种方式是要定义的Interceptor类要实现了Spring 的HandlerInterceptor 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter
l 第二种方式是实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。
Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerInterceptor接口
– preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件
去处理请求,则返回false。
– postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
– afterCompletion():这个方法在 DispatcherServlet完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
WebRequestInterceptor 中也定义了三个方法,我们也是通过这三个方法来实现拦截的。这三个方法都传递了同一个参数WebRequest,那么这个WebRequest是什么呢?这个WebRequest是Spring定义的一个接口,它里面的方法定义都基本跟HttpServletRequest一样,在WebRequestInterceptor中对WebRequest进行的所有操作都将同步到HttpServletRequest中,然后在当前请求中一直传递。
(1)preHandle(WebRequest request) 方法。该方法将在请求处理之前进行调用,也就是说会在Controller方法调用之前被调用。这个方法跟HandlerInterceptor中的preHandle是不同的,主要区别在于该方法的返回值是void,也就是没有返回值,所以我们一般主要用它来进行资源的准备工作,比如我们在使用Hibernate的时候可以在这个方法中准备一个Hibernate的Session对象,然后利用WebRequest的setAttribute(name,value, scope)把它放到WebRequest的属性中。这里可以说说这个setAttribute方法的第三个参数scope,该参数是一个Integer类型的。在WebRequest的父层接口RequestAttributes中对它定义了三个常量:
SCOPE_REQUEST :它的值是0 ,代表只有在request中可以访问。
SCOPE_SESSION :它的值是1 ,如果环境允许的话它代表的是一个局部的隔离的session,否则就代表普通的session,并且在该session范围内可以访问。
SCOPE_GLOBAL_SESSION:它的值是2,如果环境允许的话,它代表的是一个全局共享的session,否则就代表普通的session,并且在该session范围内可以访问。
(2)postHandle(WebRequest request, ModelMap model) 方法。该方法将在请求处理之后,也就是在Controller方法调用之后被调用,但是会在视图返回被渲染之前被调用,所以可以在这个方法里面通过改变数据模型ModelMap来改变数据的展示。该方法有两个参数,WebRequest对象是用于传递整个请求数据的,比如在preHandle中准备的数据都可以通过WebRequest来传递和访问;ModelMap就是Controller处理之后返回的Model对象,我们可以通过改变它的属性来改变返回的Model模型。
(3)afterCompletion(WebRequest request, Exception ex) 方法。该方法会在整个请求处理完成,也就是在视图返回并被渲染之后执行。所以在该方法中可以进行资源的释放操作。而WebRequest参数就可以把我们在preHandle中准备的资源传递到这里进行释放。Exception参数表示的是当前请求的异常对象,如果在Controller中抛出的异常已经被Spring的异常处理器给处理了的话,那么这个异常对象就是是null。
18.2 把定义的拦截器类加到SpringMVC的拦截体系中
<beansxmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <mvc:interceptors> <!--使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 --> <beanclass="com.host.app.web.interceptor.AllInterceptor"/> <mvc:interceptor> <mvc:mappingpath="/test/number.do"/> <!--定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 --> <beanclass="com.host.app.web.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>
由上面的示例可以看出可以利用mvc:interceptors标签声明一系列的拦截器,然后它们就可以形成一个拦截器链,拦截器的执行顺序是按声明的先后顺序执行的,先声明的拦截器中的preHandle方法会先执行,然而它的postHandle方法和afterCompletion方法却会后执行。
在mvc:interceptors标签下声明interceptor主要有两种方式:
(1)直接定义一个Interceptor实现类的bean对象。使用这种方式声明的Interceptor拦截器将会对所有的请求进行拦截。
(2)使用mvc:interceptor标签进行声明。使用这种方式进行声明的Interceptor可以通过mvc:mapping子标签来定义需要进行拦截的请求路径。
经过上述两步之后,定义的拦截器就会发生作用对特定的请求进行拦截了。
19.异常处理
无论做什么项目,进行异常处理都是非常有必要的,而且你不能把一些只有程序员才能看懂的错误代码抛给用户去看,所以这时候进行统一的异常处理,展现一个比较友好的错误页面就显得很有必要了。跟其他MVC框架一样,springMVC也有自己的异常处理机制。
springMVC提供的异常处理主要有两种方式:l 一种是直接实现自己的HandlerExceptionResolver,当然这也包括使用Spring已经为我们提供好的SimpleMappingExceptionResolver和DefaultHandlerExceptionResolver
l 一种是使用注解的方式实现一个专门用于处理异常的Controller——ExceptionHandler
19. 1 自定义异常处理
public class ExceptionHandler implementsHandlerExceptionResolver { @Override publicModelAndView resolveException(HttpServletRequest request, HttpServletResponseresponse, Object handler, Exception ex) { // TODOAuto-generated method stub if (exinstanceof NumberFormatException) { //doSomething... returnnew ModelAndView("number"); } else if(ex instanceof NullPointerException) { //doSomething... returnnew ModelAndView("null"); } return newModelAndView("exception"); } } 注册异常处理器 <bean id="exceptionResolver"class="com.web.handler.ExceptionHandler"/>
19.2 使用SpringMVC预定异常处理器
使用了 <mvc:annotation-driven/>配置默认装配的 HandlerExceptionResolver:
v ExceptionHandlerExceptionResolver
v ResponseStatusExceptionResolver
v DefaultHandlerExceptionResolver
19.2.1 ExceptionHandlerExceptionResolver
主要处理 Handler中用 @ExceptionHandler注解定义的方法。
• @ExceptionHandler 注解定义的方法优先级问题:例如发生的是NullPointerException,但是声明的异常有RuntimeException和 Exception,此候会根据异常的最近继承关系找到继承深度最浅的那个 @ExceptionHandler注解方法,即标记了 RuntimeException 的方法
• ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler注解的话,会找
@ControllerAdvice 中的@ExceptionHandler注解方法
19.2.2 ResponseStatusExceptionResolver
在异常及异常父类中找到 @ResponseStatus注解,然后使用这个注解的属性进行处理。
• 定义一个 @ResponseStatus注解修饰的异常类
•若在处理器方法中抛出了上述异常:
若ExceptionHandlerExceptionResolver不解析述异常。由于触发的异常 UnauthorizedException带有@ResponseStatus注解。因此会被ResponseStatusExceptionResolver解析到。最后响应HttpStatus.UNAUTHORIZED代码给客户端。HttpStatus.UNAUTHORIZED代表响应码401,无权限。关于其他的响应码请参考 HttpStatus 枚举类型源码。
19.2.3 DefaultHandlerExceptionResolver
对一些特殊的异常进行处理,比如:
NoSuchRequestHandlingMethodException
HttpRequestMethodNotSupportedException
HttpMediaTypeNotSupportedException
HttpMediaTypeNotAcceptableException
等。
19.2.4 SimpleMappingExceptionResolver
如果希望对所有异常进行统一处理,可以使用SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常
<beanclass="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <propkey="NumberFormatException">number</prop> <!-- 表示当抛出NumberFormatException的时候就返回名叫number的视图 --> <propkey="NullPointerException">null</prop> </props> </property> <propertyname="defaultErrorView" value="exception"/> <!-- 表示当抛出异常但没有在exceptionMappings里面找到对应的异常时返回名叫exception的视图--> <propertyname="statusCodes"><!--定义在发生异常时视图跟返回码的对应关系 --> <props> <propkey="number">500</prop> <!-- 表示在发生NumberFormatException时返回视图number,然后这里定义发生异常时视图number对应的HttpServletResponse的返回码是500 --> <propkey="null">503</prop> </props> </property> <propertyname="defaultStatusCode" value="404"/> <!--表示在发生异常时默认的HttpServletResponse的返回码是多少,默认是200 --> </bean>