@RequestMapping("/emps")
public String list(Map map){
map.put("employees", employeeDao.getAll());
return "list";
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Insert title here
没有任何员工信息.
ID
LastName
Email
Gender
Department
Edit
Delete
${emp.id }
${emp.lastName }
${emp.email }
${emp.gender == 0 ? 'Female' : 'Male' }
${emp.department.departmentName }
Edit
Delete
Add New Employee
@RequestMapping(value="/emp", method=RequestMethod.GET)
public String input(Map map){
map.put("departments", departmentDao.getDepartments());
map.put("employee", new Employee());
return "input";
}
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Insert title here
LastName:
<%-- 对于 _method 不能使用 form:hidden 标签, 因为 modelAttribute 对应的 bean 中没有 _method 这个属性 --%>
<%--
--%>
Email:
<%
Map genders = new HashMap();
genders.put("1", "Male");
genders.put("0", "Female");
request.setAttribute("genders", genders);
%>
Gender:
Department:
Birth:
Salary:
@RequestMapping(value="/emp", method=RequestMethod.POST)
public String save(@Valid Employee employee, Errors result,
Map map){
System.out.println("save: " + employee);
if(result.getErrorCount() > 0){
System.out.println("³ö´íÁË!");
for(FieldError error:result.getFieldErrors()){
System.out.println(error.getField() + ":" + error.getDefaultMessage());
}
map.put("departments", departmentDao.getDepartments());
return "input";
}
employeeDao.save(employee);
return "redirect:/emps";
}
@RequestMapping(value="/emp/{id}", method=RequestMethod.DELETE)
public String delete(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/emps";
}
@ModelAttribute
public void getEmployee(@RequestParam(value="id",required=false) Integer id,
Map map){
if(id != null){
map.put("employee", employeeDao.get(id));
}
}
@RequestMapping(value="/emp", method=RequestMethod.PUT)
public String update(Employee employee){
employeeDao.save(employee);
return "redirect:/emps";
}
@RequestMapping(value="/emp/{id}", method=RequestMethod.GET)
public String input(@PathVariable("id") Integer id, Map map){
map.put("employee", employeeDao.get(id));
map.put("departments", departmentDao.getDepartments());
return "input";
}
优雅的REST风格的资源URL不希望带.html或.do等后缀。
若将DispatcherServlet请求映射配置为/,则SpringMVC将捕获WEB容器的所有请求,包括静态资源的请求。
可以在SpringMVC的配置文件中配置
-
-一般WEB应用服务器默认的Servlet的名称是default。若所使用的WEB服务器的默认Servlet名称不是default,则需要通过default- servlet-name 属性显示指定。
注意这个时候必须还要
SpringMVC主框架将ServletRequest对象及目标方法的入参实例传递给WebDataBinderFactory实例,以创建DataBinder实例对象。
DataBinder调用装配在SpringMVC上下文中的ConversionService组件进行数据类型的转换、数据格式化工作。将Servlet中的请求信息填充到入参对象中。
调用Validator组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果BindingData对象。
SpringMVC抽取BindingResult中的入参对象和校验错误对象,将它们赋给处理方法的响应入参。
SpringMVC通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。数据绑定的核心部件是DataBinder。运行机制:
ConversionService converters =
– 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 ......
ConversionService是Spring类型转换的核心接口。可以利用ConversionServiceFactoryBean在Spring的IOC容器中定义一个ConversionService。
Spring将自动识别出IOC容器中的ConversionService,并在Bean属性配置及SpringMVC处理方法入参绑定等场合使用它进行数据等转换。
可通过ConversionServiceFactoryBean的converters属性注册自定义类型转换器。
Spring定义了3种类型的转换器接口,实现任意一种转换器接口都可以作为自定义转换器注册到ConversionServiceFactroyBean中:
Converter:将S类型转换为T类型对象。
ConverterFactory:将相同系列多个“同质”Converter封装在一起。如果想一种类型的对象转换为另一种类型及其子类的对象(例如String转换为Number及Number的子类Integer、?Long、?Double等等)可以使用该转换器工厂类。
GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换。
package com.atguigu.springmvc.converters;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import com.atguigu.springmvc.crud.entities.Department;
import com.atguigu.springmvc.crud.entities.Employee;
@Component
public class EmployeeConverter implements Converter {
@Override
public Employee convert(String source) {
if(source != null){
String [] vals = source.split("-");
//[email protected]
if(vals != null && vals.length == 4){
String lastName = vals[0];
String email = vals[1];
Integer gender = Integer.parseInt(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;
}
}
@RequestMapping("/testConversionServiceConverer")
public String testConverter(@RequestParam("employee") Employee employee){
System.out.println("save: " + employee);
employeeDao.save(employee);
return "redirect:/emps";
}
还提供以下支持:
-支持ConversionService实例对表单参数进行类型转换。
-支持使用@NumberFormat注解、?@DateTimeFormat注解完成数据类型格式化。
-支持使用@Valid注解对JavaBean实例进行JSR 303验证。
-支持使用@RequestBody和@ResponseBody注解。
由@InitBinder标识的方法,可以对WebDataBinder对象进行初始化。WebDataBinder是DataBinder的子类,用于完成表单数据到JavaBean属性的绑定。
@InitBinder方法不能没有返回值,它必须声明为void。
@InitBinder方法的参数通常是WebDataBinder。
@InitBinder
public void initBinder(WebDataBinder binder){
binder.setDisallowedFields("lastName");
}
Spring在格式化模块中定义了一个实现ConversionService接口的FormattingConversionService实现类,该实现类拓展了GenericConversionService,因此它具有类型转换的功能,又具有格式化功能。
FormattingConversionService拥有一个FormattingConversionServiceFactroyBean工厂类,后者用于在Spring上下文中构造前者。
FormattingConversionServiceFactroyBean内部已经注册了:
-NumberFormatAnnotationFormatterFactroy:支持对数字类型属性使用@NumberFormat注解。
-JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性使用@DateTimeFormat注解。
装配了FormattingConversionServiceFactroyBean之后,就可以在SpringMVC入参绑定及模型数据输出时使用注解驱动。
@DateTimeFormat注解可对????java.util.Date?、java.util.Calendar、?java.long.Long 时间类型进行标注:
-pattern??????????????属性:类型为字符串。指定解析/格式化字段数据的模式,如:/??????????? ??”yyyy-MM-dd hh:mm:ss”?? ???????。
-iso属性:类型为???DateTimeFormat.ISO?????。指定解析/格式化字段数据的ISO模式。包括四种:/??????? ?ISO.NONE?????(不使用)--默认、 ???ISO.DATE(yyyy-MM-dd)、 ?ISO.TIME(hh:mm:ss.SSSZ)?、ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ)。
-style属性:字符串类型。通过样式指定日期时间的格式,由两位字符组成,第一位字符表示日期的格式,第二位表示时间的格式:S:短日期/时间格式、M:中。。。、L:长。。。、F:完整。。。、-:忽略。。。
@NumberFormat可对类似数字类型的属性进行标注,它拥有两个互斥的属性:
-style:类型为NumberFormat.Style。用于指定样式类型,包括三种:Style.NUMBER(正常数字类型)、Style.CURRENCY(货币类型)、Style.PERCENT(百分数类型)。
-pattern:类型为String,自定义样式。如pattern="#,###";
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;
@NumberFormat(pattern="#,###,###.#")
private Float salary;
JSR 303是Java为Bean的数据合法性校验提供的标准框架,它已经包含在了JavaEE 6.0中。
JSR 303通过在Bean属性上标注类似@NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。
Hibernate Validator是JSR 303的一个参考实现,除了支持所有标准的校验注解外,它还支持:
需要的Jar包:
然后需要Spring容器中定义一个LocalValidatorFactoryBean;
然后通过在处理方法的入参上标注@valid注解
@NotEmpty
private String lastName;
@Email
private String email;
@Past
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;
@RequestMapping(value="/emp", method=RequestMethod.POST)
public String save(@Valid Employee employee, Errors result,
Map map){
System.out.println("save: " + employee);
if(result.getErrorCount() > 0){
System.out.println("");
for(FieldError error:result.getFieldErrors()){
System.out.println(error.getField() + ":" + error.getDefaultMessage());
}
map.put("departments", departmentDao.getDepartments());
return "input";
}
employeeDao.save(employee);
return "redirect:/emps";
}
Errors接口提供了获取错误信息的方法,如getErrorCount()、getFieldErrors(String field)。
BindingResult拓展了Errors接口。
需要验证的Bean需要和其绑定结果对象或错误对象成对出现。
常用方法:
– FieldError getFieldError(String field)
– List
– Object getFieldValue(String field)
– Int getErrorCount()
每个属性在数据绑定和数据校验发生错误时,都会生成一个对应的FieldError对象。
当一个属性验证失败后,校验框架会为该属性生成4个消息代码,这些代码以校验注解名为前缀,结合modleAttribute、属性名及属性类型名生成多个对应的消息代码:例如User中的password标注了一个@Pattern注解,当password不满足要求时会产生4个错误代码:
– Pattern.user.password
– Pattern.password
– Pattern.java.lang.String
– Pattern
还有数据绑定时数据类型不匹配时的typeMismatch;必要参数不存在required;调用处理方法出错methodInvocation等等。
NotEmpty.employee.lastName=^^LastName\u4E0D\u80FD\u4E3A\u7A7A.
Email.employee.email=Email\u5730\u5740\u4E0D\u5408\u6CD5
Past.employee.birth=Birth\u4E0D\u80FD\u662F\u4E00\u4E2A\u5C06\u6765\u7684\u65F6\u95F4.
typeMismatch.employee.birth=Birth\u4E0D\u662F\u4E00\u4E2A\u65E5\u671F.
i18n.user=User
i18n.password=Password
NotEmpty.employee.lastName=^^LastName\u4E0D\u80FD\u4E3A\u7A7A.
Email.employee.email=Email\u5730\u5740\u4E0D\u5408\u6CD5
Past.employee.birth=Birth\u4E0D\u80FD\u662F\u4E00\u4E2A\u5C06\u6765\u7684\u65F6\u95F4.
typeMismatch.employee.birth=Birth\u4E0D\u662F\u4E00\u4E2A\u65E5\u671F.
i18n.user=\u7528\u6237\u540D
i18n.password=\u5BC6\u7801
NotEmpty.employee.lastName=^^LastName\u4E0D\u80FD\u4E3A\u7A7A.
Email.employee.email=Email\u5730\u5740\u4E0D\u5408\u6CD5
Past.employee.birth=Birth\u4E0D\u80FD\u662F\u4E00\u4E2A\u5C06\u6765\u7684\u65F6\u95F4.
typeMismatch.employee.birth=Birth\u4E0D\u662F\u4E00\u4E2A\u65E5\u671F.
i18n.user=User
i18n.password=Password
当使用SpringMVC标签显示错误消息的时候,SpringMVC会查看WEB上下文是否装配了国际化消息。