0
点赞
收藏
分享

微信扫一扫

在Spring Boot中自定义ConverterFactory

梅梅的时光 2022-02-04 阅读 23

我的项目环境:
spring-boot 2.6.2
java version 1.8

下面是我的maven pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>spring-learning-converter</module>
    </modules>
    <packaging>pom</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <java.version>1.8</java.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

首先建一个Animal类和它的子类:

public class Animal {
    public void run() {
        System.out.println("run.");
    }

    public static <T extends Animal> T getAnimal(String feature,Class<T> targetClass) {
        if (Dog.class == targetClass) {
            return (T)new Dog(feature);
        } else if (Lion.class == targetClass) {
            return (T) new Lion(feature);
        } else if (Tiger.class == targetClass) {
            return (T) new Tiger(feature);
        } else if (Pig.class == targetClass) {
            return (T) new Pig(feature);
        } else {
            throw new IllegalArgumentException("Cannot convert String ["
                    + feature + "] to target class ["
                    + targetClass.getName() + "]");
        }
    }
}
public class Tiger extends Animal {
    private Feature feature;

    public Tiger(String feature) {
        this.feature = new Feature(feature);
    }

    public Feature getFeature() {
        return feature;
    }

    public void setFeature(Feature feature) {
        this.feature = feature;
    }
}
public class Lion extends Animal {
    private Feature feature;

    public Lion(String feature) {
        this.feature = new Feature(feature);
    }

    public Feature getFeature() {
        return feature;
    }

    public void setFeature(Feature feature) {
        this.feature = feature;
    }
}
public class Dog extends Animal {
    private Feature feature;

    public Dog(String feature) {
        this.feature = new Feature(feature);
    }

    public Feature getFeature() {
        return feature;
    }

    public void setFeature(Feature feature) {
        this.feature = feature;
    }
}

Animal子类中的描述动物特征的类:Feature

public class Feature {
    private String behave;

    public Feature() {}

    public Feature(String behave) {
        this.behave = behave;
    }

    public String getBehave() {
        return behave;
    }

    public void setBehave(String behave) {
        this.behave = behave;
    }
}

下面写一个String -> Animal的ConverterFactory类:

@Component
public class StringToAnimalConverterFactory implements ConverterFactory<String,Animal> {

    @Override
    public <T extends Animal> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToAnimalConverter<>(targetType);
    }

    private final class StringToAnimalConverter<T extends Animal> implements Converter<String,T> {

        private Class<T> animalType;

        public StringToAnimalConverter(Class<T> animalType) {
            this.animalType = animalType;
        }

        @Override
        public T convert(String source) {
            Feature feature = new Feature(source);

            return (T) Animal.getAnimal(source,animalType);
        }
    }
}

上面这个转换器工厂类在Spring Boot环境中只需要加@Component注解就行了,不需要在其它地方注册,就能自动的注册进去。

最后写个Controller测试下:

@RestController
public class MyController extends CommonController{

    @GetMapping("/findAnimal")
    public String findAnimal(@RequestParam("feature") Lion animal) {
        return animal.getFeature().getBehave();
    }
}

用postman发起请求:
kingofgrasslands
如果想要把字符串转换成老虎,只需要把参数改成Tiger类就行了。如下:

@RestController
public class MyController extends CommonController{

    @GetMapping("/findAnimal")
    public String findAnimal(@RequestParam("feature") Tiger animal) {
        return animal.getFeature().getBehave();
    }
}

请求结果如下:
king_of_forest
另一个Dog类和上面一样,就不测试了。

需要注意的一点是:

方法参数前面的@RequestParam(“feature")一定要加,不然就找不到转换器,返回值为空。如下:

@RestController
public class MyController extends CommonController{

    @GetMapping("/findAnimal")
    public String findAnimal(Tiger animal) {
        return animal.getFeature().getBehave();
    }
}

返回空:
返回空
当然,因为只是测试,有些地方的就省略了参数的校验,下面看下StringToNumberConverterFactory的源码,大家写自己的类时,可以参考:


package org.springframework.core.convert.support;

import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.NumberUtils;

final class StringToNumberConverterFactory implements ConverterFactory<String, Number> {
    StringToNumberConverterFactory() {
    }

    public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToNumberConverterFactory.StringToNumber(targetType);
    }

    private static final class StringToNumber<T extends Number> implements Converter<String, T> {
        private final Class<T> targetType;

        public StringToNumber(Class<T> targetType) {
            this.targetType = targetType;
        }

        @Nullable
        public T convert(String source) {
            return source.isEmpty() ? null : NumberUtils.parseNumber(source, this.targetType);
        }
    }
}

还有convert()方法中的解析操作NumberUtils.parseNumber(source,this.targetType):

    public static <T extends Number> T parseNumber(String text, Class<T> targetClass) {
        Assert.notNull(text, "Text must not be null");
        Assert.notNull(targetClass, "Target class must not be null");
        String trimmed = StringUtils.trimAllWhitespace(text);
        if (Byte.class == targetClass) {
            return isHexNumber(trimmed) ? Byte.decode(trimmed) : Byte.valueOf(trimmed);
        } else if (Short.class == targetClass) {
            return isHexNumber(trimmed) ? Short.decode(trimmed) : Short.valueOf(trimmed);
        } else if (Integer.class == targetClass) {
            return isHexNumber(trimmed) ? Integer.decode(trimmed) : Integer.valueOf(trimmed);
        } else if (Long.class == targetClass) {
            return isHexNumber(trimmed) ? Long.decode(trimmed) : Long.valueOf(trimmed);
        } else if (BigInteger.class == targetClass) {
            return isHexNumber(trimmed) ? decodeBigInteger(trimmed) : new BigInteger(trimmed);
        } else if (Float.class == targetClass) {
            return Float.valueOf(trimmed);
        } else if (Double.class == targetClass) {
            return Double.valueOf(trimmed);
        } else if (BigDecimal.class != targetClass && Number.class != targetClass) {
            throw new IllegalArgumentException("Cannot convert String [" + text + "] to target class [" + targetClass.getName() + "]");
        } else {
            return new BigDecimal(trimmed);
        }
    }

先写到这吧,如果还有其它的地方需要注意或错误,我没想到,望指正。

举报

相关推荐

0 条评论