大数跨境
0
0

SpringBoot强大的数据格式化功能

SpringBoot强大的数据格式化功能 Spring全家桶实战案例
2024-06-08
2
导读:Springboot强大的数据格式化功能你必须要知道

环境:Springboot2.7.18


1. 简介

Spring core.convert包是一个通用类型转换系统。它提供了统一的ConversionService API和强类型Converter SPI,用于实现从一种类型到另一种类型的转换逻辑。关于Spring类型转换的强大功能,查看下面这篇文章:

【必备技能】Spring数据类型转换,让你的代码更优雅!

但是当你需要格式化展示一些信息时,如本地化展示String,Converter并不提供这功能,而为了解决此类问题Spring从3.0开始引入了Formatter,当你需要解析和打印本地化字段值(个性化输出)时,使用Formatter将非常方便的实现数据的处理。

Formatter

Formatter 实现字段格式化逻辑非常简单,而且是强类型的。接口定义:

public interface Formatter<T> extends Printer<T>, Parser<T> {}

Formatter 从PrinterParser构建块接口扩展而来。以下列表显示了这两个接口的定义:

// 从目标类型到字符串的转换public interface Printer<T> {  String print(T fieldValue, Locale locale);}// Parser,从字符串到目标类型的解析public interface Parser<T> {  T parse(String clientValue, Locale locale) throws ParseException;}

要创建自己的Formatter格式化程序,只需要实现上面的Formatter接口。将泛型T替换为需要格式化的对象类型 — 例如,java.util.Date。实现print()操作以打印T的实例以在客户端区域中显示。实现parse()操作,从字符串类型到目标类型T的转换。

2. 实战案例

2.1 自定义Formatter程序

根据用户输入的信息,每个字段信息通过逗号分割,通过Formatter程序将其转换为Users对象。如输入:张三,30;将信息解析为Users对象。

public class Users {  private String name ;  private Integer age ;  // getters, setters}

自定义格式化类

public class UsersFormatter implements Formatter<Users> {  @Override  public String print(Users object, Locale locale) {    if (Objects.isNull(object)) {      return "" ;    }    return "【name = " + object.getName() + ", age = " + object.getAge() + "】" ;  }  @Override  public Users parse(String text, Locale locale) throws ParseException {    if (text == null || text.trim().length() == 0) {      return null ;    }    Users user = new Users() ;    // 下面做简单处理,不做校验    String[] values = text.split(",") ;    user.setName(values[0]) ;    user.setAge(Integer.parseInt(values[1]));    return user ;  }}

接下来是需要将上面的处理程序注册到系统中。

@Configurationpublic class WebConfig implements WebMvcConfigurer {
@Override public void addFormatters(FormatterRegistry registry) { registry.addFormatter(new UsersFormatter()) ;  }}

测试接口

@GetMapping("/save")public Object save(Users users) {  return users ;}

输出结果

2.2 基于注解的Formatter

可以按字段类型或注解配置字段格式。要将注解绑定到格式化程序,需要实现
AnnotationFormatterFactory。接口的定义

public interface AnnotationFormatterFactory<A extends Annotation> {
Set<Class<?>> getFieldTypes();
Printer<?> getPrinter(A annotation, Class<?> fieldType);
Parser<?> getParser(A annotation, Class<?> fieldType);}
  • getFieldTypes:返回可以使用注释的字段类型,那些类型的字段上可以添加自定义的注解。

  • getPrinter:返回Printer以打印带注释字段的值。

  • getParser:返回一个Parser来解析带注释字段的值。

自定义注解

自定义注解类,使用到该注解的字段都会被处理。

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})public @interface AgeFormat {}

自定义注解处理程序

public final class AgeFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<AgeFormat{  public Set<Class<?>> getFieldTypes() {    Set<Class<?>> types = new HashSet<Class<?>>() ;    types.add(Integer.class) ;    return types;  }
@Override public Printer<Integer> getPrinter(AgeFormat annotation, Class<?> fieldType) { return new AgeFormatter() ; }
@Override public Parser<Integer> getParser(AgeFormat annotation, Class<?> fieldType) { return new AgeFormatter() ; }
private class AgeFormatter implements Formatter<Integer> { @Override public String print(Integer object, Locale locale) { if (object == null) { return "" ; } return object.toString() ; }
@Override public Integer parse(String text, Locale locale) throws ParseException { if (text == null || text.trim().length() == 0) { return -1 ; } return Integer.parseInt(text.substring(1)) ; } }
}

注册格式化程序

@Configurationpublic class WebConfig implements WebMvcConfigurer {  @Override  public void addFormatters(FormatterRegistry registry) {    registry.addFormatterForFieldAnnotation(new AgeFormatAnnotationFormatterFactory()) ;  }}

字段添加注解

public class Users {  private String name ;  @AgeFormat  private Integer age ;}

测试接口

@GetMapping("/save2")public Object save2(Users users) {  return users ;}

注解添加到参数上

定义方式与上面基本一致

public final class UsersFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<UsersFormat{  public Set<Class<?>> getFieldTypes() {    Set<Class<?>> types = new HashSet<Class<?>>() ;    types.add(Users.class) ;    return types;  }
@Override public Printer<?> getPrinter(UsersFormat annotation, Class<?> fieldType) { return new UsersFormatter(); }
@Override public Parser<?> getParser(UsersFormat annotation, Class<?> fieldType) { return new UsersFormatter() ; }
}

测试接口

@GetMapping("/save")public Object save(@UsersFormat Users users) {  return users ;}

以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

紧急!Spring Boot安全漏洞

SpringBoot非常实用的一个功能,你肯定不知道

提升系统吞吐量,详解JDK21虚拟线程,炸裂

玩转Redis!非常强大的Redisson分布式集合,少写60%代码

这才是Spring为什么不支持static字段注入的原因【源码分析】

Spring Boot 3太强:全新Controller接口定义方式

强烈建议JDK升级到17,因为这些功能

Spring这个大坑要注意啦!会导致资源泄漏

Spring注入还可以这样玩!涨知识了

Spring6.2新特性@Fallback候选Bean

基于注解的Controller接口这些高级功能你都知道吗?


【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读38
粉丝0
内容832