SpringMVC的数据转换,格式化和数据校验

时间:2023-03-09 17:31:55
SpringMVC的数据转换,格式化和数据校验
      在SpringMVC中,根据请求方法签名不同,将请求消息中的消息以一定的方式转换并绑定到请求方法的参数中,在请求信息到达真正调用处理方法的这一段时间内,SpringMVC还会完成很多其他的工作,包括了请求信息转换,数据转换,数据格式化以及数据效验;
      下面的内容分为三部分,数据转换,数据格式化和数据校验;
        数据转换:我们知道,有时候数据之间不同的情况是有出现的,像是date数据类型和String数据类型的转换;这个时候就需要我们来自定义编写一个转换器来进行转换数据类型了,其中,又有三种数据类型转换器,分别是ConversionService装配的自定义转换器;@InitBinder装配的自定义编辑器;通过WebBindingInitializer接口装配的全局自定义编辑器;下面一一进行介绍;
        ConversionService装配的自定义转换器;这种转换器主要是通过实现Converter接口来实现的,并在XML中进行配置,便可以在任何控制器的处理方法中使用这个转换器了,我给它的定义是默认的转换器;
        下面是代码块;
<h3>注册页面</h3>
<form action = "register" method = "post">
<table>
<tr>
<td><label>登录名</label></td>
<td><input type = "text" id = "loginname" name = "loginname"></td>
</tr>
<tr>
<td><label>生日:</label></td>
<td><input type = "text" id = "birthday" name = "birthday"></td>
</tr>
<tr>
<td><input id = "submit" type = "submit" value = "登录"></td>
</tr>
</table>
</form>

  registerForm.jsp是一个简单的注册页面,其传递一个登录名和一个用户的生日信息;

public clas User implements Serializable{
private String loginname;
private Date birthday;
public User(){
super();
}
public String getLoginname(){
return loginname;
}
public void setLoginname(){
this.loginname = loginname;
}
public Date getBirthday(){
return birthday;
}
public void setBirthday(Date birthday){
this.birthday = birthday;
}

  下面是控制器

@Controller
public class UserController{
private static final Log logger = LogFactory.getLog(UserController.class);
@RequestMapping(value = "/{formName}")
public String loginForm(@PathVariable String formName){
return formName;
}
@RequestMapping(value = "/register",method = RequestMethod.POST)
public String register(@ModelAttribute User use, Model model){
logger.info(user);
model.addAttribute("user",user);
return "success";
}
}

  接下来,开发自定义的转换器,将传递的字符串转换成Date类型;

public class StringToDateConverter implements Converter<String,Date>{
private String datePattern;
public void setDatePattern(String datePattern){
this.datePattern = datePattern;
}
@Override
public Date convert(String date){
try{
SimpleDateFormat dateFormat = new SimpleDateFormat(this.datePattern);
return dateFormat.parse(date);
}catch(Exception e){
e.printStackTrace();
System.out.println("日期转换失败");
return null;
}
}
}

  在springmvc-config.xml中加入自定义字符转换器;

<mvc:annotation-driven conversion-service = "conversionService"/>
<bean id = "conversionService"
class = "org.springframework.context.support.ConversionServiceFactoryBean">
<property name= "converters">
<list>
<bean class = "org.fkit.converter.StringToDateConverter"
p:datePattern = "yyyy-MM-dd"/></bean>
</list>
</property>
</bean>

  在success.jsp界面中的代码:

<body>
登录名:${requestScope.user.loginname}<br>
生日:<fmt:formaDate value = "${requestScope.user.birthday}"
pattern = "yyyy年MM月dd日"/><br>
</body>

  接下来是@InitBinder自定义编辑转换器;这个编辑器是通过在Controller中注册自定义编辑器来实现的;先让我们来编写一个编辑转换器,然后用@InitBinder来注入到Controller中;

public class DateEditor extends PropertyEditorSupport{
@Override
public void setAsText(String text) throws IllegalArgumentException{
SimpleDateFormat dateFormat = new SimpleDateFormaat("yyyy-MM-dd");
try{
Date date = dateFormat.parse(text);
setValue(date);
}catch(ParseException e){
e.printStackTrace();
}
}
}

  下面是注入转换器的控制器;

@InitBinder
public void initBinder(WebDataBinder binder){
binder.registerCustomEditor(Date.class,new DateEditor());
}

  接下来是全局自定义编辑转换器;通过实现WebBindingInitiallizer接口来实现;

public class DateBindingInitializer implements WebBindingInitializer{
@Override
public void initBinder(WebDataBinder binder,WebRequest request){
binder.registerCustomEditor(Date.class,new DateEditor());
}
}

  在springmvc-config.xml文件中配置全局的自定义编辑器;

<bean
class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name = "webBindingInitializer">
<bean class = "org.fkjava.binding.DateBindingInitializer"/>
</property>
</bean>

  

在这三种转换器中,优先顺序分别为
    1,查询通过@InitBinder装配的自定义编辑器;
    2,查询通过ConversionService装配的自定义转换器;
    3,查询通过WebBindingInitializer接口装配的全局自定义编辑器;
数据格式化;
我们前面提到的Converter转换器进行源类型对象到目标类型对象的转换,Spring的转换器并不承担输入以及输出信息格式化的工作;所以也就是说,我们接下来要的讲的格式化,是指不仅进行了信息的转换,同时也进行了信息的格式化工作,通过Formatter来实现,同时还有一种注解的方式;
先做一个Formatter格式器;
public class DateFormatter implements Formatter<Date>{
private String datePattern;
private SimpleDateFormat dateFormat;
public DateFOrmatter(String datePattern){
this.datePattern = datePattern;
this.dateFormat = new SimpleDateFormat(datePattern);
}
@Override
public String print(Date date,Locale locale){
return dateFormat.format(date);
}
@Override
public Date parse(String source,Locale locale) throws ParseException{
try{
return dateFormat.parse(source);
}catch(Exception e){
throw new IllegalArgumentException();
}
}
}

  接下来再springmvc-config.xml中装配自定义格式化转换器;

<mvc:annotation-driven conversion-service = "coversionService"/>
<bean id = "conversionService"
class = "org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name = "formatters">
<list>
<bean class = "org.fkit.formatter.DateFormatter" c:_0 = "yyyy-MM-dd"/>
</list>
</property>
</bean>

  接下来,如果要使用org.springframework.format.datetime包中提供的DateFormatter实现类完成字符串到对象的转换,则只需要在配置文件中配置就可以了。

<mvc:annotation-driven conversion-service = "conversionService"/>
<bean id = "conversionService"
class = "org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name = "formatters">
<list>
<bean class = "org.springframework.format.datetime.DateFormatter"
p:pattern = "yyyy-MM-dd"/>
</list>
<property>
</bean>

  使用FormatterRegistrar注册Formatter;这个是将FormatterRegistrar作为接口来实现,所以在配置是不需要再注册任何Formatter了,而是注册Registrar;

<mvc:annotation-driven conversion-service = "conversionService"/>
<bean id = "dateFormatter" class = "org.fkit.formatter.DateFormatter" c:_0 = "yyyy-MM-dd"/>
<bean id = "conversionService"
class = "org.spirngframework.format.support.FormattingConversionServiceFactoryBean">
<set>
<bean class = "org.fkit.formatter.MyFormatterRegistrar"
p:dateFormatter-ref = "dateFormatter"/>
</set>
</property>
</bean>

  也可以通过注解来实现数据的格式化;

<h3>测试表单数据格式化</h3>
<form action = "test" method = "post">
<table>
<tr>
<td><label>日期类型:</label></td>
<td><input type = "text" id = "birthday" name = "brithday"></td>
</tr>
<tr>
<td><label>整数类型:</label></td>
<td><input type = "text" id = "total" name = "total"></td>
</tr>
<tr>
<td><label>百分数类型:</label></td>
<td><input type = "text" id = "discount" name = "discount"></td>
</tr>
<tr>
<td><label>货币类型:</label></td>
<td><input type = "text" id = "money" name = "money"></td>
</tr>
<tr>
<td><input id = "submit" type = "submit" value = "提交"></td>
</tr>
</table>
</form>

  这里的注解是用在模型数据中的;

public class User implements Serializable{
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
@NumberFormat(style = Style.NUMBER,pattern = "#,###")
private int total;
@NumberFormat(style = Style.PERCENT)
private double discount;
@NumberFormat(style = Style.CURRENCY)
private double money;
//省略set/get方法
}

  下面是控制器;

@Controller
public class FormatterController{
private static final Log logger = LogFactory.getLog(FormatterController.class);
@RequestMapping(value = "/{formName}")
public String loginForm(@PathVariable String formName){
return formName;
}
@RequestMapping(value = "/test",method = RequestMethod.POST)
public String test(
@ModelAttribute User user;
Model model){
logger.info(user);
model.addAttribute("user",user);
return "success";
}
}

  success.jsp代码

<@ taglib prefix = "form" uri = "http://www.springframework.org/tags/form" %>
<h3>测试表单数据格式化</h3>
<form:form modelAttribute = "user" method = "post" action = "">
<table>
<tr>
<td>日期类型:</td>
<td><form:input path = "birthday"/></td>
</tr>
<tr>
<td>整数类型:</td>
<td><form:input path = "total"/></td>
</tr>
<tr>
<td>百分数类型:</td>
<td><form:input path = "discount"/></td>
</tr>
<tr>
<td>货币类型:</td>
<td><form:input path = "money"/></td>
</tr>
</table>
</form:form>

  而这种自动装配是不需要特别配置的,只要默认的就行;

<mvc:annotation-driven/>
  接下来是数据校验的;
  数据校验有两种方法,一个是Validation校验,一个是JSR3.0;测试Spring的Validation校验;
<@ taglib prefix = "form" uri = "http://www.springframework.org/tags/form" %>
<html>
<head>
</head>
<body>
<form:form modelAttribute = "user" method = "post" action = "login">
<table>
<tr>
<td>登录名:</td>
<td><form:input path = "loginname"></td>
<td><form:errors path = "loginname" cssStyle = "color:red"/></td>
</tr>
<tr>
<td>密码:</td>
<td><form:input path = "password"></td>
<td><form:errors path = "password" cssStyle = "color:red"/></td>
</tr>
<tr>
<td><input type = "submit" value = "提交"/></td>
</tr>
</table>
</form:form>
</body>
</html>

  再写一个Validator类来进行校验,称为校验器;

@Repository("userValidator")
public class UserValidator implements Validator{
@Override
public boolean supports(Class<?> clazz){
return user.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target,Errors errors){
ValidationUtils.rejectIfEmpty(errors, "loginname", null, "登录名不能为空");
ValidationUtils.rejectIfEmpty(errors, "password", null, "密码不能为空");
User user = (User)target;
if(user.getLoginname().length() > 10){
errors.rejectValue("loginname",null,"用户名不能超过10个字符");
}
if(user.getPassword() != null
&& !user.getPassword().equals("")
&& user.getPassword().length() < 6){
errors.rejectValue("password",null,"密码不能小于6位");
}
}
}

  通过实现Validator接口来实现校验器;然后只需要在控制器中注入校验器即可,采用对象的方式来实现;

@Autowired
@Qualifier("UserValidator")
private UserValidator userValidator;
@RequestMapping(value = "/login",method = RequestMethod.POST)
public String login(
@ModelAttribute User user,
Model model,
Errors errors){
logger.info(user);
model.addAttribute("user",user);
userValidator.validate(user,errors);
if(errors.hasErrors()){
return "loginForm";
}
return "success";
}

  JSR3.0的话就是各种封装好的注解;同样是用在模型数据类中;

public class User implements Serializable{
@Notblank(message = "登录名不能为空")
private String loginname;
@NotBlank(message = "密码不能为空")
@Length(min = 6,max = 8,message = "密码长度必须在6到8之间")
private String password;
@NotBlank(message = "用户名不能为空")
private String username;
@Range(min = 15,max = 60,message = "年龄必须在15岁到60岁之间")
private int age;
@Email(message = "必须是合法的邮箱地址")
private String email;
@DateTimeFormate(pattern = "yyyy-MM-dd")
@Past(message = "生日必须是一个过去的日期")
private Date birthDate;
}

  在控制器中只需要在引入模型数据之前做一下@Valid就可以了

@RequestMapping(value = "/login",method = RequestMethod.POST)
public String login(
@Valid @ModelAttribute User user,
Errors errors,
Model model){
logger.info(user);
if(errors.hasErrors())
return "regsiterForm";
model.addAttribute("user",user);
return "success";
}