欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Formatter<T> 对Spring MVC接受的参数格式化

程序员文章站 2022-05-13 20:04:33
...
Formatter和Converter一样,也是将一种类型转换成另一种类型。但是,Formatter的源类型必须是一个String。

在使用时,必须编写一个实现org.springframework.format.Formatter接口的java类。这个接口的声明如下

注意点就是:此Formatter的应用场景多在Spring MVC中接受String的值将其转化为相应的Java对象

public interface Formatter<T> extends Printer<T>, Parser<T> {
}
public interface Printer<T> {
    String print(T var1, Locale var2);
}
public interface Parser<T> {
    T parse(String var1, Locale var2) throws ParseException;
}

例子:

将DateFormatter作为Formatter的例子:  (DateFormatter Spring自带支持,当然也可以自定义)

1.编写处理类

public class DateFormatter implements Formatter<Date> {

    private String pattern;

    public DateFormatter(String pattern) {
        this.pattern = pattern;
    }

    @Override
    public Date parse(String formatted, Locale locale) throws ParseException {
        if (StringUtils.isEmpty(formatted)) {
            return null;
        }
        return getDateFormatter(locale).parse(formatted);
    }

    @Override
    public String print(Date object, Locale locale) {
        return Objects.isNull(object) ? "" :
                getDateFormatter(locale).format(object);

    }

    protected DateFormat getDateFormatter(Locale local) {
        DateFormat dateFormat = new SimpleDateFormat(this.pattern, local);
        dateFormat.setLenient(false);
        return dateFormat;
    }
}

2.将处理类注册到容器  容器会默认的奖器注册到解析器中

    @Bean
    public DateFormatter dateFormatterDate() {
        return new DateFormatter("yyyy-MM/dd");
    }

3.由于容器会默认的注册到解析器中,因而该步骤也可以不要  注册到解析器

    @Bean
    public FormatterRegistrar formatterRegistrarDate() {
        return registry -> registry.addFormatter(dateFormatterDate());
    }

FormatterRegistrar用于注册多个相关的转换器或格式化器(根据给定的格式化目录注册,例如Date格式化)在直接注册不能实现时FormatterRegistrar就派上用场了,例如,当格式化程序需要在不同于自身<T>的特定字段类型下进行索引时,或者在注册Printer/Parser对时。

4.测试:

编写测试类

@Data
public class MyModel {

    private Date decimal;
}
    /**
     * 127.0.0.1:8886/get3?decimal=2017-01/01
     *
     * @return
     */
    @GetMapping(value = "/get3")
    public Object get(MyModel myModel) throws IOException {
        System.out.println(myModel);
        return myModel;
    }

同时Spring也提供了基于注解的格式化

例如 :如果使用下列注解,默认默认的解析器就会加载

@DateTimeFormat(pattern="yyyy-MM/dd")

@NumberFormat(style = NumberFormat.Style.CURRENCY)

使用注解的例子:

1.编写测试类

@Data
public class MyModel {

    @DateTimeFormat(pattern="yyyy-MM/dd")
    private Date decimal;
}
/**
     * 127.0.0.1:8886/get3?decimal=2017-01/01
     *
     * @return
     */
    @GetMapping(value = "/get3")
    public Object get(MyModel myModel) throws IOException {
        System.out.println(myModel);
        return myModel;
    }

可以达到和上面同样的效果。

同时也可以自定义注解,需要实现AnnotationFormatterFactory<T> 例如下面的Spring中用于将String转化为Number的实现

public class NumberFormatAnnotationFormatterFactory implements
        AnnotationFormatterFactory<NumberFormat> {  //NumberFormat为注解类型

    @Override
    public Set<Class<?>> getFieldTypes() {
        /**
         * 返回支持的转换类型
         */
        return new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Short.class, Integer.class, Long.class,
                Float.class, Double.class, BigDecimal.class, BigInteger.class}));
    }

    @Override
    public Printer<Number> getPrinter(NumberFormat annotation, Class<?> fieldType) {
        return configureFormatterForm(annotation, fieldType);
    }

    @Override
    public Parser<Number> getParser(NumberFormat annotation, Class<?> fieldType) {
        return configureFormatterForm(annotation, fieldType);
    }

    private Formatter<Number> configureFormatterForm(NumberFormat annotation, Class<?> fieldType) {
        if (!annotation.pattern().isEmpty()) {
            return new NumberFormatter(annotation.pattern());
        } else {
            NumberFormat.Style style = annotation.style();
            if (style == NumberFormat.Style.PERCENT) {
                return new PercentFormatter();
            } else if (style == NumberFormat.Style.CURRENCY) {
                return new CurrencyFormatter();
            } else {
                return new NumberFormatter();
            }
        }
    }
}

这是想要触发格式化,只需要在字段上添加上@NumberFormat注解即可,如下

@Data
public class MyModel {

    @NumberFormat(style = NumberFormat.Style.CURRENCY)
    private Date decimal;
}

配置全局的日期和时间格式

默认情况下,不带@DateTimeFormat注解的日期和时间字段适用DateFormat.SHORT(短日期)的格式转化字符串,开发者也可以使用自定义的全局格式覆盖默认的格式。

此时需要确保Spring不注册默认的格式化器。而应该手动注册所有的格式化器,如下

    @Bean
    public FormattingConversionService conversionService() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);

        //保证仍旧支持@NumberFormat
        conversionService.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());

        //修改默认的时间格式
        DateFormatterRegistrar registrar = new DateFormatterRegistrar();
        registrar.setFormatter(new DateFormatter("yyyyMMdd"));
        registrar.registerFormatters(conversionService);
        
        return conversionService;
    }