您的位置:首页 > 编程语言 > Java开发

SpringMVC学习总结(三).SpringMVC处理静态资源和数据处理

2017-01-01 22:23 579 查看

SpringMVC处理静态资源

若将DispatcherServlet请求映射配置为/,则Spring
MVC 将捕获WEB 容器的所有请求,包括静态资源的请求,SpringMVC会将他们当成一个普通请求处理,因找不到对应处理器将导致错误。
可以在SpringMVC的配置文件中配置<mvc:default-servlet-•handler/>的方式解决静态资源的问题:

– <mvc:default-servlet-handler/> 将在SpringMVC上下文中定义一个DefaultServletHttpRequestHandler,它会对进入DispatcherServlet的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交由WEB 应用服务器默认的Servlet 处理,如果不是静态资源的请求,才由DispatcherServlet继续处理

– 一般WEB 应用服务器默认的Servlet 的名称都是default。若所使用的–WEB 服务器的默认Servlet 名称不是default,则需要通过default-servlet-name 属性显式指定

如下:直接在浏览器中输入 http://localhost:8081/script/jquery-1.9.1.min.js 导致404 无法访问,



解决:在springmvc.xml中配置

<!-- 在实际开发中通常都需配置 mvc:annotation-driven 标签, 之前的页面才不会因为配置了直接转发页面而受到影响 -->
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:default-servlet-handler/>


数据转换

数据绑定流程

• 1. Spring MVC主框架将ServletRequest对象及目标方法的入参实例传递给WebDataBinderFactory实例,以创建DataBinder实例对象

• 2. DataBinder调用装配在Spring
MVC上下文中的ConversionService组件进行数据类型转换、数据格式化工作。将Servlet 中的请求信息填充到入参对象中

• 3. 调用Validator组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果BindingData对象

• 4. Spring MVC抽取BindingResult中的入参对象和校验错误对象,将它们赋给处理方法的响应入参

Spring MVC通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。数据绑定的核心部件是DataBinder,运行机制如下:





数据转换

• Spring MVC 上下文中内建了很多转换器,可完成大多数Java 类型的转换工作。

• ConversionServiceconverters =

– java.lang.Boolean -> java.lang.String:

org.springframework.core.convert.support.ObjectToStringConverter@f874ca

– java.lang.Character-> java.lang.Number: CharacterToNumberFactory@f004c9

– java.lang.Character-> java.lang.String: ObjectToStringConverter@68a961

– java.lang.Enum-> java.lang.String: EnumToStringConverter@12f060a

– java.lang.Number-> java.lang.Character: NumberToCharacterConverter@1482ac5

– java.lang.Number-> java.lang.Number: NumberToNumberConverterFactory@126c6f

– java.lang.Number-> java.lang.String: ObjectToStringConverter@14888e8

– java.lang.String-> java.lang.Boolean: StringToBooleanConverter@1ca6626

– java.lang.String-> java.lang.Character: StringToCharacterConverter@1143800

– java.lang.String-> java.lang.Enum: StringToEnumConverterFactory@1bba86e

– java.lang.String-> java.lang.Number: StringToNumberConverterFactory@18d2c12

– java.lang.String-> java.util.Locale: StringToLocaleConverter@3598e1

– java.lang.String-> java.util.Properties: StringToPropertiesConverter@c90828

– java.lang.String-> java.util.UUID: StringToUUIDConverter@a42f23

– java.util.Locale-> java.lang.String: ObjectToStringConverter@c7e20a

– java.util.Properties-> java.lang.String: PropertiesToStringConverter@367a7f

– java.util.UUID-> java.lang.String: ObjectToStringConverter@112b07f ......

自定义类型转换器

<!-- 将字符串转换为uesr对象 -->
<form action="/index" method="post">

<!-- id-name-age-email 例如: 1-admin-23-admin@zto.com -->
<input type="text" name="user">
<input type="submit" value="Submit"/>
</form>


/**
*
* @ClassName:  SpringMVCHandler
* @Description:核心控制类
* @author: xyc
* @date:   2017年1月1日 下午10:52:27
*
*/
@Controller
public class SpringMVCHandler {

@RequestMapping("/index")
public String toIndex(@RequestParam("user") User user) {
System.out.println("User: " + user);
return "success";
}
}


/**
*
* @ClassName:  UserConverter
* @Description:自定义类型转换器
* @author: xyc
* @date:   2017年1月1日 下午10:36:13
*
*/
@Component
public class UserConverter implements Converter<String, User> {

/**
* 将字符串截取并转换为 user 对象
* <p>Title: convert</p>
* <p>Description: </p>
* @param source
* @return
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public User convert(String source) {
String[] vals = source.split("-");

if(vals != null && vals.length == 4){
Integer id = Integer.parseInt(vals[0]);
String name = vals[1];
Integer age = Integer.parseInt(vals[2]);
String email = vals[3];

User user = new User(id, name, age, email);

return user;
}
return null;
}
}
<!-- 配置自定义类型转换器 -->
<bean id="formattingConversion"
class="org.springframework.format.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="userConverter" />
</set>
</property>
</bean>

<!--将自定义类型转换器加入mvc:annotation-driven -->
<mvc:annotation-driven conversion-service="formattingConversion"></mvc:annotation-driven>


测试结果:



Spring 支持的转换器

Spring 定义了3 种类型的转换器接口,实现任意一个转换器接口都可作为自定义转换器注册到ConversionServiceFactory中:

– Converter<S,T>:将S 类型对象转为T 类型对象

– ConverterFactory:将相同系列多个“同质”Converter 封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将String转换为Number 及Number 子类(Integer、Long、Double 等)对象)可使用该转换器工厂类

– GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换

<mvc:annotation-driven conversion-service=“conversionService”/>会将自定义的ConversionService注册到Spring
MVC 的上下文中

关于mvc:annotation-driven

• <mvc:annotation-driven/>会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter

与ExceptionHandlerExceptionResolver三个bean。

• 还将提供以下支持:

– 支持使用ConversionService实例对表单参数进行类型转换(不加的话就没有ConversionService)

– 支持使用@NumberFormat、@DateTimeFormat注解完成数据类型的格式化

– 支持使用@Valid注解对JavaBean 实例进行JSR
303验证

– 支持使用@RequestBody和@ResponseBody注解



@InitBinder

• 由@InitBinder标识的方法,可以对WebDataBinder对象进行初始化。WebDataBinder是DataBinder的子类,用于完成由表单字段到JavaBean 属性的绑定

• @InitBinder方法不能有返回值,它必须声明为void。

• @InitBinder方法的参数通常是WebDataBinder

//name不进行赋值,(不自动绑定对象中的name属性,另行处理)    user的角色赋值的时候可能会用到
@InitBinder
public void initBinder(WebDataBinder binder){
binder.setDisallowedFields("name");
}


数据格式化

• 对属性对象的输入/输出进行格式化,从其本质上讲依然属于“类型转换”的范畴。

• Spring 在格式化模块中定义了一个实现ConversionService接口的FormattingConversionService实现类,该实现类扩展了GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能

• FormattingConversionService拥有一个FormattingConversionServiceFactroyBean工厂类,后者用于在Spring 上下文中构造前者

• FormattingConversionServiceFactroyBean内部已经注册了:

– NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性使用@NumberFormat注解

– JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性使用@DateTimeFormat注解

• 装配了FormattingConversionServiceFactroyBean后,就可以在Spring
MVC 入参绑定及模型数据输出时使用注解驱动了。<mvc:annotation-driven/> 默认创建的ConversionService 实例即为 FormattingConversionServiceFactroyBean

日期格式化

• @DateTimeFormat注解可对java.util.Date、java.util.Calendar、java.long.Long时间类型进行标注:

– pattern 属性:类型为字符串。指定解析/格式化字段数据的模式,如:”yyyy-MM-ddhh:mm:ss”

– iso属性:类型为DateTimeFormat.ISO。指定解析/格式化字段数据的ISO模式,包括四种:ISO.NONE(不使用)-- 默认、ISO.DATE(yyyy-MM-dd) 、ISO.TIME(hh:mm:ss.SSSZ)、ISO.DATE_TIME(yyyy-MM-ddhh:mm:ss.SSSZ)

– style 属性:字符串类型。通过样式指定日期时间的格式,由两位字符组成,第一位表示日期的格式,第二位表示时间的格式:S:短日期/时间格式、M:中日期/时间格式、L:长日期/时间格式、F:完整日期/时间格式、-:忽略日期或时间格式

数值格式化

• @NumberFormat可对类似数字类型的属性进行标注,它拥有两个互斥的属性:

– style:类型为NumberFormat.Style。用于指定样式类型,包括三种:Style.NUMBER(正常数字类型)、Style.CURRENCY(货币类型)、Style.PERCENT(百分数类型)

– pattern:类型为String,自定义样式,如patter="#,###";#号代表数字



格式化示例

①.加入注解驱动
<mvc:annotation-driven></mvc:annotation-driven>


②.编写实体类
public class Emp {

private String name;

private Integer age;

private String email;

@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;

@NumberFormat(pattern="#,###.#")
private Float salary;

//getter and setter

@Override
public String toString() {
return "Emp [name=" + name + ", age=" + age + ", email=" + email + ", birth=" + birth + ", salary="
+ salary + "]";
}
}
③.控制层
/**
*
* @Title: saveEmp
* @Description: 测试数据格式化
* @param: @param emp
* @param: @return
* @return: String
* @throws
*/
@RequestMapping("/emp")
public String saveEmp(Emp emp){
System.out.println("emp:"+emp);
return "success";
}

④.jsp页面
<form action="/emp" method="post">
name:<input type="text" name="name"><br>
age:<input type="text" name="age"><br>
email:<input type="text" name="email"><br>
birth:<input type="text" name="birth"><br>
salary:<input type="text" name="salary"><br>
<input type="submit" value="submit">
</form>


测试结果:





如果需要既具有类型转换的功能,又具有格式化的功能
<!--既具有类型转换的功能,又具有格式化的功能   需要将org.springframework.format.support.ConversionServiceFactoryBean 变成  org.springframework.format.support.FormattingConversionServiceFactoryBean-->
<!-- 配置自定义类型转换器 -->
<bean id="formattingConversion"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="userConverter" />
</set>
</property>
</bean>

<!--将自定义类型转换器加入mvc:annotation-driven -->
<mvc:annotation-driven conversion-service="formattingConversion"></mvc:annotation-driven>


如果类型转换失败:错误信息会放到BindingResult中

/**
*
* @Title: saveEmp
* @Description: 测试数据格式化
* @param: @param emp
* @param: @return
* @return: String
* @throws
*/
@RequestMapping("/emp")
public String saveEmp(Emp emp,BindingResult result){
System.out.println("emp:"+emp);

if(result.getErrorCount() > 0){
System.out.println("出错了...");

for (FieldError error : result.getFieldErrors()) {
System.out.println(error.getField()+":"+error.getDefaultMessage());
}
}
return "success";
}


继续测试:





如上:出错的消息如何进行国际化,并且显示到页面呢?

数据校验

JSR 303

• JSR
303是Java 为Bean 数据合法性校验提供的标准框架,它已经包含在JavaEE
6.0中

• JSR 303通过在Bean 属性上标注类似于@NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对Bean 进行验证




Hibernate
Validator扩展注解

hibernate Validator是JSR
303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解




如何进行数据校验?

①.使用 JSR 303 验证标准

②.加入 hibernate validator 验证框架
<!-- hibernate-validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.0.Alpha1</version>
</dependency>


③.在spring mvc 配置文件中加入注解驱动<mvc:annotation-driven></mvc:annotation-driven>
<mvc:annotation-driven></mvc:annotation-driven>


④.需要在实体 bean 的属性上添加对应的验证注解
public class Emp {

@NotEmpty
private String name;

private Integer age;

@Email
private String email;

@Past
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;

@NumberFormat(pattern="#,###.#")
private Float salary;

//getter and setter

}


⑤.在目标方法的bean 类型前面添加@valid注解
/**
*
* @Title: saveEmp
* @Description: 测试数据格式化
* @param: @param emp
* @param: @return
* @return: String
* @throws
*/
@RequestMapping("/emp")
public String saveEmp(@Valid Emp emp,BindingResult result){
System.out.println("emp:"+emp);

if(result.getErrorCount() > 0){
System.out.println("出错了...");

for (FieldError error : result.getFieldErrors()) {
System.out.println(error.getField()+":"+error.getDefaultMessage());
}
}
return "success";
}


测试:





验证出错后 跳转到指定页面?
/**
*
* @Title: saveEmp
* @Description: 测试数据格式化
* @param: @param emp
* @param: @return
* @return: String
* @throws
*/
@RequestMapping("/emp")
public String saveEmp(@Valid Emp emp,BindingResult result){
System.out.println("emp:"+emp);

if(result.getErrorCount() > 0){
System.out.println("出错了...");

for (FieldError error : result.getFieldErrors()) {
System.out.println(error.getField()+":"+error.getDefaultMessage());
}
//出错之后跳转到input.jsp页面
return "input";
}
return "success";
}

在页面上显示错误

• Spring MVC 除了会将表单/命令对象的校验结果保存到对应的BindingResult或Errors 对象中外,还会将所有校验结果保存到“隐含模型”

• 即使处理方法的签名中没有对应于表单/命令对象的结果入参,校验结果也会保存在“隐含对象”中。

• 隐含模型中的所有数据最终将通过HttpServletRequest的属性列表暴露给JSP 视图对象,因此在JSP 中可以获取错误信息

• 在JSP 页面上可通过<form:errorspath=“userName”> 显示错误消息

<form:form action="/emp" modelAttribute="emp" method="post">
name:<input type="text" name="name">
<form:errors path="name"></form:errors>
<br>
age:<input type="text" name="age"><br>
email:<input type="text" name="email">
<form:errors path="email"></form:errors>
<br>
birth:<input type="text" name="birth">
<form:errors path="birth"></form:errors>
<br>
salary:<input type="text" name="salary"><br>
<input type="submit" value="submit">
</form:form>


jsp中通过引入<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

使用<form:errors path="属性名称"></form:errors>进行显示

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: