数据类型的转换、格式化、校验

1、数据绑定流程

1. Spring MVC 主框架将 ServletRequest 对象及目标方
法的入参实例传递给 WebDataBinderFactory 实例,以创
建 DataBinder 实例对象
2. DataBinder 调用装配在 Spring MVC 上下文中的 
ConversionService 组件进行数据类型转换、数据格式
化工作。将 Servlet 中的请求信息填充到入参对象中
3. 调用 Validator 组件对已经绑定了请求消息的入参对象
进行数据合法性校验,并最终生成数据绑定结果
BindingData 对象
4. Spring MVC 抽取 BindingResult 中的入参对象和校验
错误对象,将它们赋给处理方法的响应入参

自定义类型转换器(了解)

前台页面

<form action="testConversionServiceConverer" method="post">
Employee:<input type="text" name="employee" />
<input type="submit" value="Submit" />
</form>

转换器类(要实现converter接口)

package com.oracle.converters;

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import com.oracle.entities.Department;
import com.oracle.entities.Employee;

@Component
public class MyConverter implements Converter<String, Employee> {

@Override
public Employee convert(String source) {
if(source != null){
String[] vals = source.split("-");
if(vals != null&&vals.length==3){
String lastName = vals[0];
Integer gender = Integer.parseInt(vals[1]);
Department department = new Department();
department.setId(Integer.parseInt(vals[2]));
Employee employee = new Employee(null, lastName, gender, department);
return employee;
}
}
return null;
}

}

spring mvc配置文件中配置

<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!-- 配置自定义拦截器 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myConverter"/>
</set>
</property>
</bean>

在控制类中使用

@RequestMapping("testConversionServiceConverer")
public String test(@RequestParam("employee") Employee employee){
employeeDao.save(employee);
return "redirect:/springmvc/listall";
}

关于 mvc:annotation-driven

<mvc:annotation-driven /> 会自动注
册RequestMappingHandlerMapping
、RequestMappingHandlerAdapter 与
ExceptionHandlerExceptionResolver 三个bean。
还将提供以下支持:
支持使用 ConversionService 实例对表单参数进行类型转换 –
支持使用 @NumberFormat annotation、@DateTimeFormat –
注解完成数据类型的格式化
支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证 –
支持使用 @RequestBody 和 @ResponseBody 注解

InitBinder注解

注解的作用:

由 @InitBinder 标识的方法,可以对 WebDataBinder 对
象进行初始化

WebDataBinder的作用

①WebDataBinder 是 DataBinder 的子类,用
于完成由表单字段到 JavaBean 属性的绑定

②完成数据类型的转换,数据校验

③如果在数据转换和校验的过程中,出现错误信息,通过返回BindingResult,显示错误信息

实例:

@InitBinder
public void initBinder(WebDataBinder binder){
binder.setDisallowedFields("lastName");
}

数据格式化

操作步骤

①在spring mvc 的配置文件中配置<mvc:annotation-driven></mvc:annotation-driven>

②在对应的实体类的属性上加上注解,例如

@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;
@NumberFormat(pattern="#,###,#.#")
private float salary;

格式化原理

对属性对象的输入/输出进行格式化,从其本质上讲依然
属于 “类型转换” 的范畴。
Spring 在格式化模块中定义了一个实现
ConversionService 接口的
FormattingConversionService 实现类,该实现类扩展
了 GenericConversionService,因此它既具有类型转换的
功能,又具有格式化的功能
FormattingConversionService 拥有一个
FormattingConversionServiceFactroyBean 工厂类,
后者用于在 Spring 上下文中构造前者

FormattingConversionServiceFactroyBean  内部已经注册了 :
NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性 –
使用 @NumberFormat 注解
JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期– 类型
的属性使用 @DateTimeFormat 注解
装配了 FormattingConversionServiceFactroyBean 后,就可
以在 Spring MVC 入参绑定及模型数据输出时使用注解驱动
了。<mvc:annotation-driven/> 默认创建的
ConversionService 实例即为
FormattingConversionServiceFactroyBean

BindingResult

BindingResult中存放了处理的异常信息,可以通过入参是获取到BindingResult,进而获取到异常信息

@RequestMapping(value="/add",method=RequestMethod.POST)
public String save(Employee employee,BindingResult result){
System.out.println(employee);
if(result.getErrorCount()>0){
for(FieldError error:result.getFieldErrors()){
System.out.println(error.getField() + ":" + error.getDefaultMessage());
}
}
employeeDao.save(employee);
return "redirect:/springmvc/listall";
}

数据校验

①. 使用 JSR 303 验证标准

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

②. 加入 hibernate validator 验证框架的 jar 包

在官网下载hibernate validator的jar包

加入以下六个jar包

classmate-1.1.0.jar
hibernate-validator-5.2.1.Final.jar
hibernate-validator-annotation-processor-5.2.1.Final.jar
hibernate-validator-cdi-5.2.1.Final.jar
jboss-logging-3.2.1.Final.jar
validation-api-1.1.0.Final.jar

③. 在 SpringMVC 配置文件中添加 <mvc:annotation-driven />
④. 需要在 bean 的属性上添加对应的注解

@NotEmpty
private String lastName;

@Email
private String email;

⑤. 在目标方法 bean 类型的前面添加 @Valid 注解

通过在处理方法的入参上标
注 @valid 注解即可让 Spring MVC 在完成数据绑定后执行
数据校验的工作

2). 验证出错转向到哪一个页面 ?
注意: 需校验的 Bean 对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参

错误消息的显示和国际化

jsp页面显示

显示全部错误消息

<form:errors path="*"></form:errors>

显示在对应的记录位置

LastName:<form:input path="lastName"/><br>
<form:errors path="lastName"></form:errors>

国际化错误消息

当使用 Spring MVC 标签显示错误消息时, Spring MVC 会查看
WEB 上下文是否装配了对应的国际化消息,如果没有,则显示默认
的错误消息,否则使用国际化消息。

①i18n.properties

当一个属性校验失败后,校验框架会为该属性生成 4 个消 
息代码,这些代码以校验注解类名为前缀,结合
modleAttribute、属性名及属性类型名生成多个对应的消
息代码

例如

NotEmpty.employee.lastName=\u540D\u5B57\u4E0D\u80FD\u4E3A\u7A7A
Past.employee.birth = \u751F\u65E5\u5FC5\u987B\u662F\u4E00\u4E2A\u8FC7\u53BB\u7684\u65F6\u95F4

②配置国际化消息

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>

③补充

若数据类型转换或数据格式转换时发生错误,或该有的参
数不存在,或调用处理方法时发生错误,都会在隐含模型
中创建错误消息。其错误代码前缀说明如下:
required:必要的参数不存在。如 @RequiredParam(“param1”) –
标注了一个入参,但是该参数不存在
typeMismatch:在数据绑定时,发生数据类型不匹配的问题 –
methodInvocation:Spring MVC 在调用处理方法时发生了错误

ajax

①加入jackson的jar包

jackson-annotations-2.4.0.jar
jackson-core-2.4.5.jar
jackson-databind-2.4.6.1.jar

②前台发送ajax请求

$(function(){
$("#id").click(function(){
var url = this.href;
var args={};
$.post(url,args,function(data){
for(var i=0;i<data.length;i++){
var id = data[i].id
var lastName = data[i].lastName
alert(id+":"+lastName);
}
});
return false;
});
})

③后台通过配置@ResponseBody和方法的返回值类型返回json数据

@ResponseBody
@RequestMapping("ajax")
public Collection<Employee> testJson(){
return employeeDao.getEmployees();
}

实现原理

通过HttpMessageConverter<T>

上传下载

①添加jar包

commons-fileupload-1.2.1.jar
commons-io-2.0.jar

②配置springmvc 的配置文件

<!-- 配置 MultipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="1024000"></property>
</bean>

上传的页面

<form action="testFileUpload" method="POST" enctype="multipart/form-data">
File: <input type="file" name="file"/>
Desc: <input type="text" name="desc"/>
<input type="submit" value="Submit"/>
</form>

后台处理

@RequestMapping("/testFileUpload")
public String testFileUpload(@RequestParam("desc") String desc,
@RequestParam("file") MultipartFile file) throws IOException{
System.out.println("desc: " + desc);
System.out.println("OriginalFilename: " + file.getOriginalFilename());
System.out.println("InputStream: " + file.getInputStream());
return "success";
}

下载的页面

<a href="testResponseEntity">Test ResponseEntity</a>

后台处理

@RequestMapping("/testResponseEntity")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException{
byte [] body = null;
ServletContext servletContext = session.getServletContext();
InputStream in = servletContext.getResourceAsStream("/files/abc.txt");
body = new byte[in.available()];
in.read(body);

HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename=abc.txt");

HttpStatus statusCode = HttpStatus.OK;

ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(body, headers, statusCode);
return response;
}

国际化

关于国际化:
1. 在页面上能够根据浏览器语言设置的情况对文本(不是内容), 时间, 数值进行本地化处理
2. 可以在 bean 中获取国际化资源文件 Locale 对应的消息
3. 可以通过超链接切换 Locale, 而不再依赖于浏览器的语言设置情况

解决:
1. 使用 JSTL 的 fmt 标签
2. 在 bean 中注入 ResourceBundleMessageSource 的示例, 使用其对应的 getMessage 方法即可
3. 配置 LocalResolver 和 LocaleChangeInterceptor

拦截器

①实现HandlerInterceptor接口

package com.atguigu.springmvc.interceptors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class FirstInterceptor implements HandlerInterceptor{

/**
* 该方法在目标方法之前被调用.
* 若返回值为 true, 则继续调用后续的拦截器和目标方法.
* 若返回值为 false, 则不会再调用后续的拦截器和目标方法.
*
* 可以考虑做权限. 日志, 事务等.
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("[FirstInterceptor] preHandle");
return true;
}

/**
* 调用目标方法之后, 但渲染视图之前.
* 可以对请求域中的属性或视图做出修改.
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("[FirstInterceptor] postHandle");
}

/**
* 渲染视图之后被调用. 释放资源
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("[FirstInterceptor] afterCompletion");
}

}

②配置文件中配置

<mvc:interceptors>
  <!-- 配置自定义的拦截器 -->
  <bean class="com.atguigu.springmvc.interceptors.FirstInterceptor"></bean>
</mvc:interceptors>

拦截器补充

<mvc:interceptors>
<!-- 配置自定义的拦截器 -->

  <!-- <mvc:mapping path="/emps"/>配置拦截器作用的路径,<mvc:exclude-mapping path="/emps"/>配置拦截器不作用的路径 -->
  <mvc:interceptor>
    <mvc:mapping path="/emps"/>
    <bean class="com.atguigu.springmvc.interceptors.SecondInterceptor"></bean>
  </mvc:interceptor>

</mvc:interceptors>

多个拦截器的执行顺序

preHandle正序

postHandle和afterCompletion倒序

异常处理

Spring MVC 通过 HandlerExceptionResolver 处理程序
的异常,包括 Handler 映射、数据绑定以及目标方法执行
时发生的异常。

ExceptionHandlerExceptionResolver

主要处理 Handler 中用 @ExceptionHandler 注解定义的
方法。用ModelAndView返回异常信息

/**
* 1. 在 @ExceptionHandler 方法的入参中可以加入 Exception 类型的参数, 该参数即对应发生的异常对象
* 2. @ExceptionHandler 方法的入参中不能传入 Map. 若希望把异常信息传导页面上, 需要使用 ModelAndView 作为返回值
* 3. @ExceptionHandler 方法标记的异常有优先级的问题. 越接近发生的异常的优先级越高
* 4. @ControllerAdvice: 如果在当前 Handler 中找不到 @ExceptionHandler 方法来出来当前方法出现的异常,
* 则将去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常.
*/

@ExceptionHandler({ArithmeticException.class})
public ModelAndView handleArithmeticException(Exception ex){
System.out.println("----> 出异常了: " + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}

去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常.

package com.atguigu.springmvc.test;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class SpringMVCTestExceptionHandler {

@ExceptionHandler({ArithmeticException.class})
public ModelAndView handleArithmeticException(Exception ex){
System.out.println("----> 出异常了: " + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}

}

ResponseStatusExceptionResolver

自定义一个返回的页面

可以作用在类上,也可以是方法上

①注册

@ResponseStatus(value=HttpStatus.FORBIDDEN, reason="用户名和密码不匹配!")
public class UserNameNotMatchPasswordException extends RuntimeException{

/**
*
*/
private static final long serialVersionUID = 1L;

}

②使用

@RequestMapping("/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
if(i == 13){
throw new UserNameNotMatchPasswordException();
}
System.out.println("testResponseStatusExceptionResolver...");

return "success";
}

也可以直接放在方法上,当调用此方法时,返回异常的页面

@ResponseStatus(reason="测试",value=HttpStatus.NOT_FOUND)
@RequestMapping("/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
if(i == 13){
throw new UserNameNotMatchPasswordException();
}
System.out.println("testResponseStatusExceptionResolver...");

return "success";
}

DefaultHandlerExceptionResolver

对一些特殊的异常进行处理,比
如NoSuchRequestHandlingMethodException、HttpReques
tMethodNotSupportedException、HttpMediaTypeNotSuppo
rtedException、HttpMediaTypeNotAcceptableException
等。

SimpleMappingExceptionResolver

如果希望对所有异常进行统一处理,可以使用 
SimpleMappingExceptionResolver,它将异常类名映射为
视图名,即发生异常时使用对应的视图报告异常

<!-- 配置使用 SimpleMappingExceptionResolver 来映射异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionAttribute" value="ex"></property>
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>

springmvc学习第四天的更多相关文章

  1. SpringMVC学习(四)——处理器Handler的各种常用实现

    代码:http://files.cnblogs.com/files/douJiangYouTiao888/MultiActionController.zip 在使用springMVC的开发过程中,Ha ...

  2. springmvc学习日志四

    一.回顾 1.文件上传 1.1引入fileupload的jar包 1.2在springmvc的配置文件中引入CommonsMutilpartResolver文件上传解析器 1.3在控制层在写入代码 2 ...

  3. SpringMVC学习笔记(四)

    一.Controller接受网页参数. 1.使用方法的形参来接受 //使用基本类型和字符串来接受 @RequestMapping(value="/param2.do") publi ...

  4. SpringMVC学习总结(四)——基于注解的SpringMVC简单介绍

    SpringMVC是一个基于DispatcherServlet的MVC框架,每一个请求最先访问的都是 DispatcherServlet,DispatcherServlet负责转发每一个Request ...

  5. springmvc学习(四)

    1.使用 @CookieValue 绑定请求中的 Cookie 值 例子: java @RequestMapping(value="/testCookieValue") publi ...

  6. SpringMVC学习(四)———— 数据回显与自定义异常处理器

    一.数据回显技术 Springmvc默认支持对pojo类型的数据回显,默认不支持简单类型的数据回显 1.1.什么是数据回显? 在信息校验时,如果发生校验错误,那么把校验的数据信息,依然停留在当前页面, ...

  7. SpringMVC学习记录四——功能开发及参数绑定

    9       商品修改功能开发 9.1      需求 操作流程: 1.进入商品查询列表页面 2.点击修改,进入商品修改页面,页面中显示了要修改的商品(从数据库查询) 要修改的商品从数据库查询,根据 ...

  8. SpringMVC 学习笔记(四) 处理模型数据

    Spring MVC 提供了下面几种途径输出模型数据: – ModelAndView: 处理方法返回值类型为 ModelAndView时, 方法体就可以通过该对象加入模型数据 – Map及Model: ...

  9. SpringMVC学习笔记四:SimpleMappingExceptionResolver异常处理

    SpringMVC的异常处理,SimpleMappingExceptionResolver只能简单的处理异常 当发生异常的时候,根据发生的异常类型跳转到指定的页面来显示异常信息 ExceptionCo ...

随机推荐

  1. 重置样式 - Eric Meyer的原版

    重置样式就是一组CSS声明,用来覆盖不同浏览器渲染HTML元素时的各种默认样式.重置样式一般会被加入到主样式文件的开头,用来将各个浏览器的自有默认样式重置成统一表现,确保样式表中后续追加的样式在不同浏 ...

  2. 如何去掉list里重复的数据

    去掉list重复的数据,目前总结的以下三种方法,分别是采用set集合来做.两层循环不用任何方法来做,以及一层循环采用contains()方法来做,如下: 1.采用set结合来做: package te ...

  3. Java 基础知识 练习题

    利用文本编辑器输入课堂上练习的Hello.java,并在JDK环境下编译和运行.请将程序编译.运行的结果截图.

  4. 【SSO单点系列】(3):CAS4.0 登录页验证码的添加

    2016.08.23 更新 注意:这个教程只适合4.0版本的,4.1以及以上的版本的已经不试用了, 后面几篇有人提到过 源码网盘链接更新了下 : 链接: http://pan.baidu.com/s/ ...

  5. HttpWebRequest调用WebAPI

    private void button1_Click(object sender, EventArgs e) { string ss= HttpPost("http://localhost: ...

  6. [转]unicode,ansi,utf-8,unicode big endian的故事

    unicode,ansi,utf-8,unicode big endian的故事很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们看到8个开关状态是好的 ...

  7. Linux 执行ll命令时指定按文件时间或大小排序

    按时间排序: $ ll -ht 按大小排序: $ ll -hS 使用--help查看命令的用法,如 $ ll --help

  8. [jetbrains系列] 外链第三方库+代码补全设置

    jetbrains系列的IDE真的是太好用了,有种相见恨晚的感觉. 在开发过程中第三方库是必不可少的,在开发的时候如果有一个可以补全的IDE可以节省查文档的时间. 举个例子:给pycharm配pysp ...

  9. [java基础]循环结构2

    [java基础]循环结构2 写了几个循环结构练习~记录一下~~ 1:99乘法表 /** 文件路径:G:\JavaByHands\循环语句\ 文件名称:GameForFor.java 编写时间:2016 ...

  10. Minimum Path Sum [LeetCode]

    Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...