软件开发实训(720科技)――第六课:转换器和格式化、验证器

软件开发实训(720科技)――第六课:转换器和格式化、验证器

内容关键词:转换、格式化、验证器
授课老师:张森鹏

一、知识笔记

1. Coonnveerrtteer r

     Spring 的 Converter 是可以将一种类型转换成另一种类型的一个对象。例如,用户输入的日期可能有许多种形式,如“December 25,2014”“12/25/2014”和“2014-12-25”,这些都表示同一个日期。默认情况下,Spring 会期待用户输入的日期样式与当前语言区域的日期样式相同。例如,对于美国的用户而言,就是月/日/年格式。如果希望 Spring 在将输入的日期字符串绑定到 LocalDate 时,使用不同的日期样式,则需要编写一个 Converter,才能将字符串转换成日期。java.time.LocalDate 类是 Java 8 的一个新类型,用来替代 java.util.Date。还需使用新的 Date/Time API 来替换旧有的 Date 和 Calendar 类。

    为了创建 Converter,必须编写实现 org.springframework.core.convert.converter. Converter接口的一个 Java 类。这个接口的声明如下:public interface Converter<S, T>       这里的 S 表示源类型,T 表示目标类型。例如,为了创建一个可以将 Long 转换成 Date的 Converter,要像下面这样声明 Converter 类:

public class MyConverter implements Converter<Long, LocalDate> {}
      在类实体中,需要编写一个来自 Converter 接口的 convert 方法实现。这个方法的签名如下:

          T convert(S source)

2. Fo or r ma at tt te er r
      Formatter 就像 Converter 一样,也是将一种类型转换成另一种类型。但是,Formatter 的源类型必须是一个 String,而 Converter 则适用于任意的源类型。Formatter 更适合 Web 层,而Converter 则可以用在任意层中。为了转换 Spring MVC 应用程序表单中的用户输入,始终应该选择 Formatter,而不是 Converter。
    为了创建Formatter,要编写一个实现org.springframework.format.Formatter接口的Java类。下面是这个接口的声明:
       public interface Formatter<T>
     这里的 T 表示输入字符串要转换的目标类型。该接口有 parse 和 print 两个方法,所有实现都必须覆盖它们。
          T parse(String text, java.util.Locale locale)
          String print(T object, java.util.Locale locale)

     parse 方法利用指定的 Locale 将一个 String 解析成目标类型。print 方法与之相反,它返回目标对象的字符串表示法。例如,formatter-demo 应用程序中用一个 LocalDateFormatter 将 String 转换成 Date。其作用与 converter-demo 中的 StringToLocalDateConverter 一样。

3.验 证 概 览
    Converter 和 Formatter 作用于字段级。在 MVC 应用程序中,它们将 String 转换或格式化成另一种 Java 类型,如 java.time.LocalDate。验证器则作用于对象级。它决定某一个对象中的所有字段是否均是有效的,以及是否遵循某些规则。一个典型的 Spring MVC 应用会同时应用到 formatters/converters 和 validators。
     如果一个应用程序中既使用了 Formatter,又有 validator(验证器),那么,应用中的事件顺序是这样的:在调用 Controller 期间,将会有一个或者多个 Formatter,试图将输入字符串转换成 domain 对象中的 field 值。一旦格式化成功,验证器就会介入。
       例如,Order 对象可能会有一个 shippingDate 属性(其类型显然为 LocalDate),它的值绝对不可能早于今天的日期。当调用 OrderController 时,DateFormatter 会将字符串转化成 Date,并将它赋予 Order 对象的 shippingDate 属性。如果转换失败,用户就会被转回到前一个表单。如果转换成功,则会调用验证器,查看 shippingDate 是否早于今天的日期。
      现在,你或许会问,将验证逻辑转移到 LocalDateFormatter 中是否更加明智?因为比较一下日期并非难事,但答案却是否定的。首先,LocalDateFormatter 还可用于将其他字符串格式化成日期,如 birthDate 或者 purchaseDate。这两个日期的规则都不同于 shippingDate。事实上,比如,员工的出生日期绝对不可能晚于今日。其次,验证器可以检验两个或更多

字段之间的关系,各字段均受不同的 Formatter 支持。例如,假设 Employee 对象有 birthDate属性和 startDate 属性,验证器就可以设定规则,使任何员工的入职日期均不可能早于他的出生日期。因此,有效的 Employee 对象必须让它的 birthDate 属性值早于其 startDate 值。这就是验证器的任务。

扫描二维码关注公众号,回复: 1443887 查看本文章

二、重要笔记

1.用 用 R Re eg gi is st tr ra ar r 注册 册 F Fo or r ma at tt te er r

package formatter;
import org.springframework.format.FormatterRegistrar;
import org.springframework.format.FormatterRegistry;
public class MyFormatterRegistrar implements FormatterRegistrar {
private String datePattern;
public MyFormatterRegistrar(String datePattern) {
this.datePattern = datePattern;
}
@Override
public void registerFormatters(FormatterRegistry registry) {
registry.addFormatter(new LocalDateFormatter(datePattern));
// register more formatters here
}
}
有了 Registrar,就不需要在 Spring MVC 配置文件中注册任何 Formatter 了,只在 Spring

配置文件中注册 Registrar 就可以了。

2.选择 择 C Co on nv ve er rt te er r , 还是 是 F Fo or r ma at tt te er r

Converter 是一般工具,可以将一种类型转换成另一种类型。例如,将 String 转换成
LocalDate,或者将 Long 转换成 LocalDate。Converter 既可以用在 Web 层,也可以用在其他
层中。
Formatter 只能将 String 转换成另一种 Java 类型。例如,将 String 转换成 LocalDate,但
它不能将 Long 转换成 LocalDate。因此,Formatter 适用于 Web 层。为此,在 Spring MVC 应

用程序中,选择 Formatter 比选择 Converter 更合适。

3. Sp pr ri in ng g 的 的 V Va al li id da at to or r 范

    spring-validator 应用程序中包含一个名为 ProductValidator 的验证器,用于验证 Product 对

象。Spring-validator 的 Product 类如清单 7.2 所示。ProductValidator 类如清单 7.3 所示。

清单 

a、 Product 类

package domain;
import java.io.Serializable;
import java.math,BigDecimal;
import java.time.LocalDate;
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String description;
private BigDecimal price;
private LocalDate productionDate;
//getters and setters methods not shown
}
b、 ProductValidator 类
package validator;
import java.math,BigDecimal;
import java.time.LocalDate;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import domain.Product;
public class ProductValidator implements Validator {
@Override
public boolean supports(Class<?> klass) {
return Product.class.isAssignableFrom(klass);
}
@Override
public void validate(Object target, Errors errors) {
Product product = (Product) target;
ValidationUtils.rejectIfEmpty(errors, "name",
"productname.required");
ValidationUtils.rejectIfEmpty(errors, "price","price.required");
ValidationUtils.rejectIfEmpty(errors, "productionDate",
"productiondate.required");
BigDecimal price = product.getPrice();
if (price != null && price.compareTo(BigDecimal.ZERO) < 0) {
errors.rejectValue("price", "price.negative");
}
Local Date productionDate = product.getProductionDate();
if (productionDate != null) {
if (productionDate.isAfter(LocalDate.now())) {
errors.rejectValue("productionDate",
"productiondate.invalid");
}
}
}
}
ProductValidator 验证器是一个非常简单的验证器。它的 validate 方法会检验 Product 是否

有名称和价格,并且价格是否不为负数。它还会确保生产日期不晚于今天。

4. JS SR R 3 30 03 3 V Va al li id da at to or r 范 例
     jsr303-validator 应用程序展示了 JSR 303 输入验证的例子。这个应用程序是对 spring-
validator 进行修改之后的版本,与之前的版本有一些区别。首先,它没有 ProductValidator 类。
其次,来自 Hibernate Validator 库的 jar 文件已经被添加到了 WEB-INF/lib 中。
清单 7.6 Product 类的 name 和 productionDate 字段已经用 JSR 303 注解类型进行了注解。
   清单 7.6 Product 类
package domain;
import java.io.Serializable;
import java.math.BigDecimal
import java.time.LocalDate;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;
public class Product implements Serializable {
private static final long serialVersionUID = 78L;
@Size(min=1, max=10)
private String name;
private String description;
private BigDecimal price;
@Past
private LocalDate productionDate;
// getters and setters not shown
}
在 ProductController 类的 saveProduct 方法中,必须用@Valid 对 Product 参数进行注解,
如清单 7.7 所示。
清单 7.7 ProductController 类
package controller;
import javax.validation.Valid;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import domain.Product;
@Controller
public class ProductController {
private static final Log logger = LogFactory
.getLog(ProductController.class);
@RequestMapping(value = "/add-product")
public String inputProduct(Model model) {
model.addAttribute("product", new Product());
return "ProductForm";
}
@RequestMapping(value = "/save-product")
public String saveProduct(@Valid @ModelAttribute Product product,
BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
FieldError fieldError = bindingResult.getFieldError();
logger.info("Code:" + fieldError.getCode() + ", object:"
+ fieldError.getObjectName() + ", field:"
+ fieldError.getField());
return "ProductForm";
}
// save product here
model.addAttribute("product", product);
return "ProductDetails";
}
}
为了定制来自验证器的错误消息,要在 messages.properties 文件中使用两个键。

三、学习参考
https://m.2cto.com/kf/201707/654979.html
https://blog.csdn.net/slowly_come_faster

猜你喜欢

转载自blog.csdn.net/xy123456789123/article/details/80074471