Spring 自定义 Converter

Spring 自定义 Converter

在上节 Spring 之请求参数解析原理 中有说到关于参数的类型转换是依靠 WebDataBinder(数据绑定器,进行数据绑定的工作)中的 conversionService(负责数据类型的转换和格式化工作 )中的各个converters (负责各种 数据类型的转换 工作)来处理的,这节来说说它~

  • 关于Spring的核心元素 DispatchServlet 请查看:Spring 原理之 DispatchServlet 原理
  • 关于 Spring 之请求参数解析原理(实体类传参解析)请查看 Spring 之请求参数解析原理(实体类传参解析)
  • 关于 Spring 请求参数类型转换解析 请查看 Spring 请求参数类型转换解析

前言

在定义一个接口时,有很多种方式来实现接口的参数接收,常用的有以下三种:

  • request 作为接口的方法参数,然后request 根据 key获取传递的参数值

    @GetMapping("/request_getValue")
    public ResponseEntity<User> requestGetValue(HttpServletRequest request){
        // request 根据 key 获取值
        String username = request.getParameter("username");
        String name = request.getParameter("name");
        User user = new User();
        user.setName(name);
        user.setUsername(username);
        return new ResponseEntity<>(user , HttpStatus.OK);
    }
    
  • 直接以方法参数的方式进接收传递的参数值

    // 直接以参数的形式获取参数值
    @GetMapping("/param_getValue")
    public ResponseEntity<User> paramGetValue(String username,  String name){
        User user = new User();
        user.setName(name);
        user.setUsername(username);
        return new ResponseEntity<>(user , HttpStatus.OK);
    }
    
  • 利用 Pojo 类 以方法参数的方式来封装获取参数值

    @GetMapping("/pojo_getValue")
    public ResponseEntity<User> pojoGetValue(User user){
        return new ResponseEntity<>(user , HttpStatus.OK);
    }
    

在上述调用接口的过程中,接口中参数的类型 与 调用接口传递数据的数据类型,会涉及到类型转换,而这些类型转换都由 WebDataBinder(数据绑定器,进行数据绑定的工作)中的 conversionService负责数据类型的转换和格式化工作 )中的各个 converters (负责各种 数据类型的转换 工作)来处理的

converters 默认是一个大小为 124 的HashMap,key 为 转换前类型->转换后类型 字符串,value 为 org.springframework.core.convert.converter.ConverterFactory 的实现类,相互对应完成数据的转换,部分举例如下:

Spring 自定义 Converter_第1张图片

自定义 Converter

如果不想依靠上面的类型转换处理,可以自定义 Converter。在上述类型转换的底层原理是通过调用 ConverterFactory 的实现类(converter HashMap中 key 对应的value值)中 Converter 实现类的 **convert **方法来处理

那么我们通过自定义实现 **ConverterFactory ** 来完成我们自己希望的类型转换,主要涉及三个步骤:

  • 自定义 Converter 类,实现 Converter 接口,复写convert() 方法,完成自己的需求
  • 注入自定义 Converter 类

以 java.lang.String -> java.time.LocalDate 的转换为例来举例说明:

自定义 Converter 类,实现 Converter 接口

编写 Converter 的实现类 LocalDateConverter 完成 String ====》LocalDate 的转换

package com.study.config;

import org.springframework.core.convert.converter.Converter;
import org.springframework.format.annotation.DateTimeFormat;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public final class LocalDateConverter implements Converter<String, LocalDate> {

    private final DateTimeFormatter formatter;

    /**
     * 根据pattern
     *
     * @param dateFormat
     */
    public LocalDateConverter(String dateFormat) {
        this.formatter = DateTimeFormatter.ofPattern(dateFormat);
    }

    /**
     * 根据ISO来指定
     *
     * @param iso
     */
    public LocalDateConverter(DateTimeFormat.ISO iso) {
        DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
        switch (iso) {
            case DATE:
                formatter = DateTimeFormatter.ISO_DATE;
            case DATE_TIME:
                formatter = DateTimeFormatter.ISO_DATE_TIME;
            default:
                formatter = DateTimeFormatter.ISO_DATE;
        }
        this.formatter = formatter;
    }

    @Override
    public LocalDate convert(String source) {
        if (source.isEmpty()) {
            return null;
        }
        return LocalDate.parse(source, formatter);
    }
}

注入自定义 Converter 类

注入 Formatters ,传入自定义的pattern / iso

package com.study.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;

@Configuration
public class MyWebMvcSupport extends WebMvcConfigurationSupport {

    @Override
    protected void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new LocalDateConverter("yyyy-MM-dd"));
        //或者
        //registry.addConverter(new LocalDateConverter(DateTimeFormat.ISO.DATE));
    }
}

1、接口编写

@GetMapping("/test_localDate")
public ResponseEntity<User> localDateValue(LocalDate date) {
    System.out.println(date);
    return new ResponseEntity<>(HttpStatus.OK);
}

2、接口调用(正常调用)

http://localhost:8081/test_localDate?date=2022-11-24

3、原理

上面的解析是通过 org.springframework.format.support.FormattingConversionService$ParserConverter 的convert 方法完成的转换,而这里调试后的convert就为我们上面编写的 LocalDateConverter 完成转换,即改变实现类型转换的convert来实现具体的业务

Spring 自定义 Converter_第2张图片

你可能感兴趣的:(JAVA,Spring,spring,java,后端)