spring mvc

来源:互联网 发布:ubuntu登陆界面鼠标 编辑:程序博客网 时间:2024/06/04 18:05

      • Ioc DI
      • bean
        • annotation wiring
      • aop 面向切面编程
      • Repository Component Service Controller
        • PostConstruct 和 PreDestroy
        • Required
        • 使用 Autowired 和 Qualifier 注解执行自动装配
        • Resource
        • Inject
  • Spring MVC 学习指南
      • MVC模型
      • 使用Flash属性用于重定向传递数据
    • 数据绑定
      • 表单标签库
    • Data Access Object
    • DispatcherServlet
    • Form对象
      • 数据绑定
    • Validation in Hibernate
      • Validator
        • validate
        • validateProperty
        • validateValue
        • ConstaintViolation methods
        • Validating groups
        • Groups sequences
      • constraints annotation
      • Valid and Validated
    • BeanWrapper BeanWrapperImpl
      • getPropertyValue setPropertyValue
    • PropertyEditor
      • Built-in PropertyEditors
    • BeanFactory
      • CustomEditorConfigurer
      • PropertyEditorRegistrar
    • Converter
      • ConverterFactory
      • GenericConverter

Ioc & DI

一个IOC container把多个bean联系在一起,使一个bean的修改不会影响到其他bean,实现了松耦合。把这个叫做控制反转或者依赖注入。

bean

https://www.tutorialspoint.com/spring/spring_bean_definition_inheritance.htm

bean可以在xml文件中定义

class 类所在的位置.类名

id 唯一的不冲突的名字

scope singleton 只使用一个实例的引用

​ prototype 每次使用创建新的实例

init-method

destroy-method

(也可以在beans中声明 default-init-method 和 default-destory-method)

lazy-initialization 为true则当第一次需要的时候创建实例,而不是开始的时候就创建

<bean id = "textEditor" class = "com.tutorialspoint.TextEditor">      <property name = "spellChecker">         <bean id = "spellChecker" class =               "com.tutorialspoint.SpellChecker"/>      </property></bean>

在bean中的property用来调用set函数,设置bean中变量的值

<bean id = "javaCollection" class = "com.tutorialspoint.JavaCollection">      <!-- results in a setAddressList(java.util.List) call -->      <property name = "addressList">         <list>            <value>INDIA</value>            <value>Pakistan</value>            <value>USA</value>            <value>USA</value>         </list>      </property>  <property name = "addressMap">         <map>            <entry key = "1" value = "INDIA"/>            <entry key = "2" value = "Pakistan"/>            <entry key = "3" value = "USA"/>            <entry key = "4" value = "USA"/>         </map>      </property>      <!-- results in a setAddressProp(java.util.Properties) call -->      <property name = "addressProp">         <props>            <prop key = "one">INDIA</prop>            <prop key = "one">INDIA</prop>            <prop key = "two">Pakistan</prop>            <prop key = "three">USA</prop>            <prop key = "four">USA</prop>         </props>      </property>  </bean>

可以用以设置list, set, map, property的值

可以向一个bean中注入另一个bean的引用

   <bean id = "..." class = "...">      <!-- Passing bean reference  for java.util.List -->      <property name = "addressList">         <list>            <ref bean = "address1"/>            <ref bean = "address2"/>            <value>Pakistan</value>         </list>      </property>      <!-- Passing bean reference  for java.util.Set -->      <property name = "addressSet">         <set>            <ref bean = "address1"/>            <ref bean = "address2"/>            <value>Pakistan</value>         </set>      </property>      <!-- Passing bean reference  for java.util.Map -->      <property name = "addressMap">         <map>            <entry key = "one" value = "INDIA"/>            <entry key = "two" value-ref = "address1"/>            <entry key = "three" value-ref = "address2"/>         </map>      </property>   </bean>

可以注入空值或者null

<bean id = "..." class = "exampleBean">   <property name = "email" value = ""/></bean><bean id = "..." class = "exampleBean">   <property name = "email"><null/></property></bean>

auto-wiring

annotation wiring

缺省没有打开

打开

<beans xmlns = "http://www.springframework.org/schema/beans"   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"   xmlns:context = "http://www.springframework.org/schema/context"   xsi:schemaLocation = "http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context-3.0.xsd">   <context:annotation-config/>   <!-- bean definitions go here --></beans>

启动自动扫描功能

 <context:component-scan base-package=”bookstore.dao” /> 

Annotating a class with the @Configuration indicates that the class can be used by the Spring IoC container as a source of bean definitions.

The @Bean annotation tells Spring that a method annotated with @Bean will return an object that should be registered as a bean in the Spring application context.

aop 面向切面编程

面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,我们知道,面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。
​ 但是人们也发现,在分散代码的同时,也增加了代码的重复性。什么意思呢?比如说,我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。
​ 也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
​ 一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。
这样看来,AOP其实只是OOP的补充而已。OOP从横向上区分出一个个的类来,而AOP则从纵向上向对象中加入特定的代码。有了AOP,OOP变得立体了。如果加上时间维度,AOP使OOP由原来的二维变为三维了,由平面变成立体了。从技术上来说,AOP基本上是通过代理机制实现的。
​ AOP在编程历史上可以说是里程碑式的,对OOP编程是一种十分有益的补充。

@Repository @Component @Service @Controller

用于DAO(Data Access Object), 把类标识为bean

  • @Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。
  • @Service 通常作用在业务层,但是目前该功能与 @Component 相同。
  • @Controller 通常作用在控制层,但是目前该功能与 @Component 相同。

通过在类上使用 @Repository、@Component、@Service 和 @Controller 注解,Spring 会自动创建相应的 BeanDefinition 对象,并注册到 ApplicationContext 中。这些类就成了 Spring 受管组件。这三个注解除了作用于不同软件层次的类,其使用方式与 @Repository 是完全相同的。

@PostConstruct 和 @PreDestroy

分别对应 init-method和destory-method

@Required

判断给定 Bean 的相应 Setter 方法是否都在实例化的时候被调用了。而不是判断字段是否已经存在值了。Spring 进行依赖检查时,只会判断属性是否使用了 Setter 注入。如果某个属性没有使用 Setter 注入,即使是通过构造函数已经为该属性注入了值,Spring 仍然认为它没有执行注入,从而抛出异常。另外,Spring 只管是否通过 Setter 执行了注入,而对注入的值却没有任何要求,即使注入的 ,Spring 也认为是执行了依赖注入。

使用 @Autowired 和 @Qualifier 注解执行自动装配

http://stackoverflow.com/questions/19414734/understanding-spring-autowired-usage

使用 @Autowired 注解进行装配,只能是根据类型进行匹配。@Autowired 注解可以用于 Setter 方法、构造函数、字段,甚至普通方法,前提是方法必须有至少一个参数。@Autowired 可以用于数组和使用泛型的集合类型。然后 Spring 会将容器中所有类型符合的 Bean 注入进来。@Autowired 标注作用于 Map 类型时,如果 Map 的 key 为 String 类型,则 Spring 会将容器中所有类型符合 Map 的 value 对应的类型的 Bean 增加进来,用 Bean 的 id 或 name 作为 Map 的 key。

当容器中存在多个 Bean 的类型与需要注入的相同时,注入将不能执行,我们可以给 @Autowired 增加一个候选值,做法是在 @Autowired 后面增加一个 @Qualifier 标注,提供一个 String 类型的值作为候选的 Bean 的名字。

@Autowired(required=false)  @Qualifier("ppp")  public void setPerson(person p){}

@Qualifier 甚至可以作用于方法的参数 ( 对于方法只有一个参数的情况,我们可以将 @Qualifer 标注放置在方法声明上面,但是推荐放置在参数前面 ),举例如下:

 @Autowired(required=false)  public void sayHello(@Qualifier("ppp")Person p,String name){}

我们可以在配置文件中指定某个 Bean 的 qualifier 名字,方法如下:

 <bean id="person" class="footmark.spring.Person">     <qualifier value="ppp"/>  </bean>

@Resource

@Resource 使用 byName 的方式执行自动封装。@Resource 标注可以作用于带一个参数的 Setter 方法、字段,以及带一个参数的普通方法上。@Resource 注解有一个 name 属性,用于指定 Bean 在配置文件中对应的名字。如果没有指定 name 属性,那么默认值就是字段或者属性的名字。@Resource 和 @Qualifier 的配合虽然仍然成立,但是 @Qualifier 对于 @Resource 而言,几乎与 name 属性等效。

如果 @Resource 没有指定 name 属性,那么使用 byName 匹配失败后,会退而使用 byType 继续匹配,如果再失败,则抛出异常。在没有为 @Resource 注解显式指定 name 属性的前提下,如果将其标注在 BeanFactory 类型、ApplicationContext 类型、ResourceLoader 类型、ApplicationEventPublisher 类型、MessageSource 类型上,那么 Spring 会自动注入这些实现类的实例,不需要额外的操作。此时 name 属性不需要指定 ( 或者指定为”“),否则注入失败;如果使用了 @Qualifier,则该注解将被忽略。而对于用户自定义类型的注入,@Qualifier 和 name 等价,并且不被忽略。

@Inject

http://stackoverflow.com/questions/19414734/understanding-spring-autowired-usage

@Inject 和 @Autowired 作用是一样的,只不过@Autowired是Spring自己的,@Inject 是 Java CDI标准规定的

Spring MVC 学习指南

依赖注入:

创建对象A和B的实例,把B的实例传给A,而不是在A中创建B的实例

因为B如果是一个接口,在A中创建B的实例只能选择一个实现类来创建,扩展性不好。

使用Spring,程序几乎把所有重要对象的创建工作移交给spring,并配置如何注入依赖,支持XML或annocation两种配置方式。

还要创建一个ApplicationContext对象,代表一个Spring控制反转容器

ApplicationContext接口有多个实现

ClassPathXmlApplicationContext:在类加载路径中加载配置文件

FileSystemXmlApplicationContext:在文件系统中加载

这两个实现都需要至少一个包含beans信息的XML文件。

对于Spring MVC应用,可以通过一个Spring Servlet来处理ApplicationContext,而无需直接处理。

ApplicationContext context = new ClassPathXmlApplicationContext(  new String[] {"config1.xml", "config2.xml"});Product product = context.getBean("product", Product.class);

构造器方式依赖注入

<bean name="product" class="app01a.bean.Product"><constructor-arg name="name" value="Ultimate" /></bean>

Setter方式依赖注入

<bean name="employee" class="app01a.bean.Employee">  <property name="homeAddress" ref="simpleAddress" />  <property name="firstName" value="Junior" /></bean><bean name="simpleAddress" class="app01a.bean.Address">  ...</bean>

MVC模型

controller — Servlet/Filter

model — JavaBeans

view — JSP页面

Serializable

HttpSession

使用Flash属性用于重定向传递数据

redirectAttributes.addFlashAttribute("message", "The product was successfully added.")return "redirect:/product_view"+saveProduct.getId();

数据绑定

使form bean失去作用

当验证失败时,它会重新生成一个HTML表单,依旧是你原来输入的值。

表单标签库

<% @taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

Data Access Object

By convention you can mark DAO classes with @Repository and services with @Service. Also the former does some persistence layer exception translation.

Since you are asking theoretically: DAO should perform raw database operations and translate them to some higher level constructs (objects, collections). Services should call DAOs and perform business operations. Typically transactions demarcation is performed on service layer to span several DAO calls.

Finally DAO should abstract business logic from persistence details, ideally allowing to switch persistence layer without business logic (services) changes. This is hardly ever possible due to leaking abstraction of persistence providers (e.g. lazy loading).

DAO直接操作数据库原始数据,并把数据转换成更高层级的对象或者集合

Service直接调用DAO的操作并进行业务操作

DispatcherServlet

DispatcherServlet是一个IOC容器,需要在web.xml中配置,并指定xml文件

<listener>    <listener-class>      org.springframework.web.context.ContextLoaderListener    </listener-class></listener><context-param>  <param-name>contextConfigLocation</param-name>  <param-value>    classpath*:spring/applicationContext.xml    classpath*:spring/spring-security.xml  </param-value></context-param><servlet>    <servlet-name>pfcase</servlet-name>    <servlet-class>       org.springframework.web.servlet.DispatcherServlet    </servlet-class>    <init-param>        <param-name>contextConfigLocation</param-name>        <param-value>              classpath*:spring/mvc-config.xml        </param-value>    </init-param>    <load-on-startup>1</load-on-startup>    <multipart-config>        <max-file-size>5242880</max-file-size><!--5MB-->        <max-request-size>20971520</max-request-size><!--20MB-->    </multipart-config></servlet><servlet-mapping>    <servlet-name>pfcase</servlet-name>    <url-pattern>/</url-pattern></servlet-mapping>

这个文件用于定义IOC容器连接的bean的位置,定义等等。

<mvc:annotation-driven/><context:component-scan base-package="com.youzan.pfcase.web" />

Form对象

需不需要使用Form对象?

举例: Product对象和ProductForm对象的实现是一样的,为什么还需要ProductForm?

因为ProductForm是前端的表单在服务端的表现方式,而表单对象带有ServletRequest,这个不应该暴露给其他层,如Product。

而且ProductForm可以进行校验,检查数据输入是否正确,不正确的话可以显示用户原输入的表单。

数据绑定

不需要使用Form对象-- 源于一个新的实现方式:数据绑定

数据绑定是将用户输入绑定到领域模型的一种特性。

数据绑定也可以实现:当输入验证失败时,会重新生成HTML表单,显示用户之前输入的值,而不用手动编写代码。

Validation in Hibernate

Field-level constraints

public class Car {  @NotNull  private String manufacturer;}

Property-level constraints

public class Car {  @NotNull  public String getManufacturer() {    return manufacturer;  }  @AssertTrue  public boolean isRegistered() {    return isRegistered;  }}

认为作用在返回值上

Class-level constraints

@PassengerCountpublic class Car {}

Constraint inheritance

约束可以通过extends父类或 implements 接口继承

Object graphs

约束可以作用在对象映射上

如果父类被验证,父类引用的被Valid标注的类也会被验证,子类同理。

public class Car {  @NotNull  @Valid  private Person driver;  @Valid  private List<Person> passengers = new ArrayList<Person>();  public Car(Person driver) {    this.driver = driver;  }  // getters and setters ...}

如果Car的一个实例被验证,引用的Person对象也会被验证,如果Person实例验证失败,Car的实例也会验证失败。

Validator

获取一个Validator的实例

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();Validator validator = factory.getValidator();

Validator接口有3个方法,可以用来验证整个entity,或者entity的一个属性。

所有的方法都返回一个 Set\,如果验证成功则为空,否则对于每个不匹配的约束添加一个ConstraintViolation的实例。

validate

validate方法用来验证给定的entity的所有约束

使用:

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();Validator validator = factory.getValidator();Car car = new Car(null);Set<ConstraintViolation<Car>> constraintViolations = validator.validate(car);assertEquals(1, constraintViolations.size());assertEquals("may not be null", constraintViolations.iterator().next().getMessage());

validateProperty

用来验证给定实例的一个named property

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();Validator validator = factory.getValidator();Car car = new Car(null);Set<ConstraintViolation<Car>> constraintViolations = validator.validatorProperty(car, "manufacturer");assertEquals(1, constraintViolations.size());assertEquals("may not be null", constraintViolations.iterator().next().getMessage());

validateValue

用来检验如果一个实例的一个属性的值给定,能否被成功验证

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();Set<ConstraintViolation<Car>> constraintViolations = validator.validateValue(Car.class, "manufacturer", null);assertEquals(1, constraintViolations.size());assertEquals("may not be null", constraintViolations.iterator().next().getMessage());

ConstaintViolation methods

https://docs.jboss.org/hibernate/validator/4.1/reference/en-US/html/validator-usingvalidator.html

getMessage()

getMessageTemplate()

getRootBean()

getRootBeanClass()

getLeafBean()

getPropertyPath()

getInvalidValue()

getConstraintDescriptor()

Validating groups

把一些约束归到一个groups中,可以只验证这个groups中的约束是否成立

public class Driver extends Person {    @Min(value = 18, message = "You have to be 18 to drive a car", groups = DriverChecks.class)    public int age;    @AssertTrue(message = "You first have to pass the driving test", groups = DriverChecks.class)    public boolean hasDrivingLicense;    public Driver(String name) {        super( name );    }    public void passedDrivingTest(boolean b) {        hasDrivingLicense = b;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }}public class Car {    @NotNull    private String manufacturer;    @NotNull    @Size(min = 2, max = 14)    private String licensePlate;    @Min(2)    private int seatCount;    @AssertTrue(message = "The car has to pass the vehicle inspection first", groups = CarChecks.class)    private boolean passedVehicleInspection;    @Valid    private Driver driver;    public Car(String manufacturer, String licencePlate, int seatCount) {        this.manufacturer = manufacturer;        this.licensePlate = licencePlate;        this.seatCount = seatCount;    }}public interface DriverChecks {}public interface CarChecks {}
constraintViolations = validator.validate( car );constraintViolations = validator.validate( car, CarChecks.class );assertEquals( 1, constraintViolations.size() );constraintViolations = validator.validate( car, DriverChecks.class );assertEquals( 1, constraintViolations.size() );// 按顺序验证assertEquals( 0, validator.validate( car, Default.class, CarChecks.class, DriverChecks.class ).size() );

// 好像又不对的样子

拥有约束的属性-属于某个规定的groups的属性 = Default的属性

如果validator.validate(car)没有第二个参数,默认为Default.class

Groups sequences

用法一:

缺省的情况下,不管约束属于哪个group,约束不按特定的顺序被评估,为了控制评估的顺序,可以用GroupSequence定义一个接口来实现。

@GroupSequence({Default.class, CarChecks.class, DriverChecks.class})public interface OrderedChecks {}

用法二:

重新定义一个类的缺省group sequence

@GroupSequence({RentalCar.class, CarChecks.class})public class RentalCar extends Car {  public RentalCar(String manufacturer, String licencePlate, int seatCount) {        super( manufacturer, licencePlate, seatCount );    }}

constraints annotation

https://docs.jboss.org/hibernate/validator/4.1/reference/en-US/html/validator-usingvalidator.html

@Valid and @Validated

As you quoted from the documentation, @Validated was added to support “validation groups”, i.e. group of fields in the validated bean. This can be used in multi step forms where you may validate name, email, etc.. in first step and then other fields in following step(s).The reason why this wasn’t added into @Valid annotation is because that it is standardized using the java community process (JSR-303), which takes time and Spring developers wanted to allow people to use this functionality sooner.

BeanWrapper & BeanWrapperImpl

in org.springframework.beans

BeanWrapper提供set和get属性值的方法(单个或者多个),提供get property descripttors 和查询属性的方法,用来判断是否可读或者可写。

而且,BeanWrapper还提供对嵌套属性的支持,允许在子属性上属性的设置(没有深度限制)。

BeanWrapper还提供不需要在目标类上添加代码就能添加标准的JavaBeans PropertyChangeListeners和VetoableChangeListeners。

最后,BeanWrapper通常不直接被用在代码中,而是使用DataBinder和BeanFactory。

getPropertyValue & setPropertyValue

BeanWrapper company = new BeanWrapperImpl(new Company());// setting the company name..company.setPropertyValue("name", "Some Company Inc.");// ... can also be done like this:PropertyValue value = new PropertyValue("name", "Some Company Inc.");company.setPropertyValue(value);// ok, let's create the director and tie it to the company:BeanWrapper jim = new BeanWrapperImpl(new Employee());jim.setPropertyValue("name", "Jim Stravinsky");company.setPropertyValue("managingDirector", jim.getWrappedInstance());// retrieving the salary of the managingDirector through the companyFloat salary = (Float) company.getPropertyValue("managingDirector.salary");

PropertyEditor

PropertyEditor用于影响Object和String之间的转换。

用处:

  • 用PropertyEditors在beans上设置属性,把String作为bean的属性值
  • 分析http request的参数

Built-in PropertyEditors

Class Explanation ByteArrayPropertyEditor Editor for byte arrays. Strings will simply be converted to their corresponding byte representations. Registered by default by BeanWrapperImpl. ClassEditor Parses Strings representing classes to actual classes and the other way around. When a class is not found, an IllegalArgumentException is thrown. Registered by default byBeanWrapperImpl. CustomBooleanEditor Customizable property editor for Booleanproperties. Registered by default byBeanWrapperImpl, but, can be overridden by registering custom instance of it as custom editor. CustomCollectionEditor Property editor for Collections, converting any source Collection to a given targetCollection type. CustomDateEditor Customizable property editor for java.util.Date, supporting a custom DateFormat. NOT registered by default. Must be user registered as needed with appropriate format. CustomNumberEditor Customizable property editor for any Number subclass like Integer, Long, Float,Double. Registered by default by BeanWrapperImpl, but can be overridden by registering custom instance of it as a custom editor. FileEditor Capable of resolving Strings to java.io.File objects. Registered by default by BeanWrapperImpl. InputStreamEditor One-way property editor, capable of taking a text string and producing (via an intermediate ResourceEditor and Resource) an InputStream, so InputStreamproperties may be directly set as Strings. Note that the default usage will not close the InputStream for you! Registered by default by BeanWrapperImpl. LocaleEditor Capable of resolving Strings to Localeobjects and vice versa (the String format is*[country]*[variant], which is the same thing the toString() method of Locale provides). Registered by default by BeanWrapperImpl. PatternEditor Capable of resolving Strings to java.util.regex.Pattern objects and vice versa. PropertiesEditor Capable of converting Strings (formatted using the format as defined in the javadocs of the java.util.Properties class) to Properties objects. Registered by default by BeanWrapperImpl. StringTrimmerEditor Property editor that trims Strings. Optionally allows transforming an empty string into a null value. NOT registered by default; must be user registered as needed. URLEditor Capable of resolving a String representation of a URL to an actual URL object. Registered by default by BeanWrapperImpl.

BeanFactory

CustomEditorConfigurer

CustomEditorConfigurer, a bean factory post-processor

能够方便地添加对额外的PropertyEditor实例到ApplicationContext的支持

public class ExoticTypeEditor extends PropertyEditorSupport {  public void setAsText(String text) {    setValue(new ExoticType(text.toUpperCase()));  }}

用CustomEditorConfigurer注册PropertyEditor

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">  <property name="customEditors">    <map>      <entry key="example.ExoticType" value="example.ExoticTypeEditor" />    </map>  </property></bean>

PropertyEditorRegistrar

在Spring container上注册 property editor的方法

特别适用于:在不同情况下需要使用相同的property editor的集合

就可以写一个对应的registrar,每次进行重用

public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {  public void registerCustomEditors(PropertyEditorRegistry registry) {    registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());  }}
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">  <property name="properyEditorRegistrars">    <list>      <ref bean="customPropertyEditorRegistrar"/>    </list>  </property></bean><bean id="customPropertyEditorRegistrar" class="com.foo.editors.spring.CustomPropertyEditorRegistrar" />

PropertyEditorRegistrars和数据绑定的Controllers(如SimpleFormController)一起使用非常方便

public final class RegisterUserController extends SimpleFormController {  private final PropertyEditorRegistrar customPropertyEditorRegistrar;  public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) {    this.customProperyEditorRegistrar = properyEditorRegistrar;  }  protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {    this.customPropertyEditorRegistrar.registerCustomEditors(binder);  }}

Converter

实现 Converter

ConverterFactory

集中转换逻辑,比如把String to Enum的转换集中在一起

public interface ConverterFactory<S, R> {  <T extends R> Converter<S, T>getConverter(Class<T>targetType);}
final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {  public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {    return new StringToEnumConverter(targetType);  }  private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {    private Class<T> enumType;    public StringToEnumConverter(Class<T> enumType) {      this.enumType = enumType;    }    public T convert(String source) {      return (T)Enum.valueOf(this.enumType, source.trim());    }  }}

GenericConverter

提供多种源和目标类型的转换

比如,允许field annotation驱动的类型转换

public interface GenericConverter {  public Set<ConvertiblePair> getConvertibleTypes();  Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);}
原创粉丝点击