SpringMVC深入三
视图及视图解析器
请求处理方法执行完成后,最终返回一个ModelAndView
对象。对于那些返回String、View或ModelMap等类型的处理方法,SpringMVC也会在内部将它们装配成一个ModelAndView
对象,它包含了逻辑名和模型对象的视图。
SpringMVC借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是JSP,也可能是Excel、JFreeChart等各种表现形式的视图。
对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现MVC的充分解耦。
视图对象由视图解析器负责实例化,由于视图是无状态的,所以它们不会有线程安全的问题。
JSP是最常见的视图技术,可以使用InternalResourceViewResolver
作为视图解析器:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
JstlView
若项目中使用了JSTL,SpringMVC会自动把视图由InternalResourceViewResolver
转为JstlView
。
若使用JSTL的fmt
标签,则需要在SpringMVC的配置文件中配置国际化资源文件。
例如:
国际化资源文件为i18n.properties
,对应创建i18n_zh_CN.properties
和i18n_en_US.properties
i18n.username=Username
i18n.password=Password
在SpringMVC的配置文件配置国际化文件:
<!-- 配置国际化资源文件-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
在JSP页面中导入fmt
标签,并使用
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
使用方式如下:
<fmt:message key="i18n.username"></fmt:message>
<fmt:message key="i18n.password"></fmt:message>
mvc:view-controller
mvc:view-controller
标签配置直接转发的页面,在事件使用时配合mvc:annotation-driven
一起使用
如下配置:
<!-- 配置直接转发的页面-->
<mvc:view-controller path="/success" view-name="success"/>
<mvc:annotation-driven></mvc:annotation-driven>
则http://localhost:8080/springmvc-1/success
直接访问success.jsp
页面
自定义视图
定义一个自定义视图:
package com.springmvc.views;
import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.View;
@Component
public class HelloView implements View {
@Override
public String getContentType() {
return "text/html";
}
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().print("hello view, time: "+new Date());
}
}
在SpringMVC的配置文件配置视图解析器BeanNameViewResolver
,使用视图的名字来解析视图,需要把view放入到IOC容器中,所以view使用了@Component
注解。
<!-- 配置视图BeanNameViewResolver解析器 -->
<!--
使用视图的名字来解析视图,通过order属性来定义视图解析器的优先级
order值越小,优先级越高
-->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="100"></property>
</bean>
通过order属性来定义视图解析器的优先级order值越小,优先级越高。
InternalResourceViewResolver
的优先级为Integer.MAX_VALUE
定义handler方法如下:
@RequestMapping("/testView")
public String testView(){
System.out.println("testView");
return "helloView";
}
重定向
如果返回的字符串中包含forward:
或redirect:
前缀,SpringMVC会对他们进行特殊处理:将forward:
和redirect:
当初指示符,其后的字符串作为URL来处理:
redirect:success.jsp
: 会完成一个到success.jsp
的重定向的操作forward:success.jsp
: 会完成一个到success.jsp
的转发操作
处理静态资源
优雅的REST风格的资源URL不希望带.html或.do等后缀。
若将DispatchServlet请求映射为/
。则SpringMVC将捕获WEB容器的所有请求,包括静态资源的请求,SpringMVC会将它们当成一个普通请求处理,因而会找不到对应处理器,导致错误。
在SpringMVC的配置文件中配置<mvc:default-servlet-handler/>
即可结解决。需配合<mvc:annotation-driven></mvc:annotation-driven>
使用
<mvc:default-servlet-handler/>
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:default-servlet-handler/>
将SpringMVC上下文中定义一二DefaultServletHttpRequestHandler
,它会对进入DispatchServlet
的请求进行筛选,如果发现是没有经过映射的请求,就将该请求交由WEB应用服务器默认的Servlet处理,如果不是静态资源的请求,才有DispatchServlet
继续处理。
一般WEB应用服务器默认的Servlet的名称都是default,若所使用的WEB服务器的默认Servlet名称不是default,则需要通过default-servlet-name属性显示指定。
数据绑定
数据绑定流程
1.SpringMVC主框架将ServletRequest对象及目标方法的入参实例传递给WebDataBinderFactory
实例,以创建DataBinder
实例对象。
2.DataBinder
调用装配在SpringMVC上下文中的ConvsersionService
组件进行数据类型转换、数据格式化工作。将Servlet中的请求信息填充到入参对象中。
3.调用Validator
组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果BindingData
对象。
4.SpringMVC抽取BindingResult
中的入参对象和校验错误对象,将它们赋给处理方法的响应入参。
数据转换
SpringMVC上下文内置了很多转换器,可以完成大多数Java类型的转换工作。
自定义类型转换器
ConversionService
是Spring类型转换体系的核心接口。
可以利用ConversionServiceFactoryBean
在Spring的IOC容器中定义ConversionService
。Spring将自动识别出IOC容器中的
ConversionService
,并在Bean属性配置及SpringMVC处理方法入参绑定等场合使用它进行数据的转换。
可通过ConversionServiceFactoryBean
的converters
属性注册自定义的类型转换器。
Spring支持的转换器
SpringMVC定义了3类型的转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到ConversionServiceFactoryBean
中:
Converter<S, T>
将S类型转为T类型对象ConverterFactory
将相同系列多个“同质”Converter封装在一起。如果希望将一种类型的对象转为另一种类型及其子类型的对象(例如将String转换为Number及Number子类(Integer、Long、Double等)对象)可以使用该转换器工厂类GenericConverter
会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换
如下的例子,会把string类型转为Employee对象。String类型的格式为lastname-email-gender-department.id
处理表单请求的handler如下:
@Controller
public class SpringMVCTest {
@Autowired
private EmployeeDao employeeDao;
@RequestMapping("/testConversionServiceConverter")
public String testConverter(@RequestParam("employee") Employee employee){
System.out.println("testConverter");
employeeDao.save(employee);
return "redirect:/emps";
}
}
自定义一个转换器EmployeeConverter
,实现Converter
接口
@Component
public class EmployeeConverter implements Converter<String, Employee> {
@Override
public Employee convert(String source) {
if (source != null) {
String[] vals = source.split("-");
if (vals != null && vals.length == 4) {
String lastName = vals[0];
String email = vals[1];
String gender = vals[2];
Department department = new Department();
department.setId(Integer.parseInt(vals[3]));
Employee employee = new Employee(null, lastName, email, gender, department);
System.out.println(source+"--convert--:"+employee);
return employee;
}
}
return null;
}
}
在SpringMVC的配置文件中配置:
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!-- 配置ConversionService -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="employeeConverter"/>
</set>
</property>
</bean>
mvc:annotation-driven
<mvc:annotation-driven/>
会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter与ExceptionHandlerExceptionResolver(异常解析器)三个bean。
还提供以下支持:
- 支持使用
ConversionService
实例对表单参数进行类型转换 - 支持使用
@NumberFormatannotation
、@DateTimeFormat
注解完成数据类型的格式化 - 支持使用
@Valid
注解对JavaBean实例进行JSR 303验证 - 支持使用
@RequsetBody
和@ResponseBody
注解
@InitBinder
由@InitBinder标识的方法,可以对WebDataBinder对象进行初始化。WebDataBinder是DataBinder的子类,用于完成由表单字段到JavaBean属性的绑定。
@InitBinder方法不能有返回值,它必须声明为void。
@InitBinder方法的参数通常是WebDataBinder
数据格式化
步骤:
1.配置<mvc:annotation-driven></mvc:annotation-driven>
2.在目标属性上加上注解即可:
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;
@NumberFormat(pattern="#,###,###.#")
可以对数值进行格式化
在数据转换环节使用了自定义的转换器,也使用了<mvc:annotation-driven></mvc:annotation-driven>
,如何才能既可以使用自定义的转换器,也可以使用SpringMVC提供的数据格式化注解?
使用org.springframework.format.support.FormattingConversionServiceFactoryBean
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!-- 配置ConversionService -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="employeeConverter"/>
</set>
</property>
</bean>
数据校验
JSR303
是Java为Bean数据合法性校验提供的标准框架,它已经包含在Java6.0中。
JSR303
通过在Bean的属性上标注类似于@NotNull
、@Max
等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。
参考:
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) Validates that the annotated string is between min and max included.
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期
@Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期
@Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式
Hibernate Validator是JSR 303的一个参考实现,除了支持所有标准的校验注解外,它还支持以下扩展注解
@Email 被注解的元素必须是电子邮箱地址
@Length 被注解的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串必须非空
@Range 被注释的元素必须在合适的范围内
SpringMVC数据校验
Spring4.0拥有自己独立的数据校验框架,同时支持JSR303标准的校验框架
Spring在进行数据绑定时,可同时调用校验框架完成数据校验工作。在SpringMVC中,可直接通过注解驱动方式进行数据校验
Spring的LocalValidatorFactoryBean
既实现了Spring的Validator接口,也实现了JSR 303的Validator接口。只要在Spring容器中定义一个LocalValidatorFactoryBean
,即可将其注入到需要数据校验的Bean中。
Spring本身并没有提供JSR 303
的实现,所以必须将JSR 303的实现者的jar包放在类路径下
1.如何校验?
<mvc:annotation-driven/>
会默认装配好一个LocalValidatorFactoryBean
,通过在处理方法的入参上标注@Valid
注解即可让SpringMVC在完成数据绑定后执行数据校验的工作。
a.使用JSR303
验证标准
b.加入hibernate validator验证框架的jar包
c.在SpringMVC配置文件添加<mvc:annotation-driven/>
d.需要在bean的属性上添加对应的注解
e.在目标方法bean的属性上添加@Valid
注解
f.添加BindingResult
参数,获取验证结果
如下的例子:
@RequestMapping(value="/emp", method=RequestMethod.POST)
public String save(@Valid Employee employee, BindingResult result) {
System.out.println("save:"+employee);
if (result.getErrorCount() > 0) {
System.out.println("出错了");
for (FieldError error : result.getFieldErrors()) {
System.out.println(error.getField() + " : " + error.getDefaultMessage());
}
//若验证出错,则转向默认的页面
}
employeeDao.save(employee);
return "redirect:/emps";
}