OpenFeign学习(六):OpenFign进行表单提交参数或传输文件

说明

在之前的博文《OkHttp的高级封装Feign学习(一): Feign注解的使用》中,我简单介绍了OpenFeign的使用方式。其中在请求传递参数时,可以使用@Param和@QueryMap注解。本篇博文我将介绍学习如何使用OpenFeign进行表单参数提交或者传输文件。

正文

我们先看下之前示例中只使用@Param和@QueryMap的局限性:
@Param注解用来解析其他注解中的参数表达式,一般用于restful风格的请求方式中。@QueryMap注解则是用来定义参数的Map集合或者是POJO。这两种方式定义的参数在请求时都会直接拼接在连接中,如 http:xxx?name1=value1&name2=value2。

在使用时我们希望以POST方式将参数以表单的形式提交。这里我做了以下尝试,将请求方式改为POST,并配置请求头ContentType为application/x-www-form-urlencoded,方法的参数使用@Param标记并使用默认的encoder。

@RequestLine("POST /test/hello2")
@Headers("Content-Type: application/x-www-form-urlencoded")
ResultPojo hello2Post(@Param("name") String name);

在执行时抛出异常,默认的ecoder不支持LinkedHashMap的编码:

feign.codec.EncodeException: class java.util.LinkedHashMap is not a type supported by this encoder.

可以发现只将ContentType设置为application/x-www-form-urlencoded并不能实现表单提交,我们需要配置特殊的encoder。对此,OpenFeign官方在feign-form项目中为我们提供了Form Encoder。

Form Encoder

OpenFeign提供的该模块支持表单application/x-www-form-urlencoded 和 multipart/form-data 两种编码。

在使用前需要添加依赖:


    io.github.openfeign.form
    feign-form
    3.8.0

之后可以直接配置Encoder

HelloService service = Feign.builder()
			.logger(new Slf4jLogger())
			.logLevel(Logger.Level.FULL)
			.client(new OkHttpClient())
//			.encoder(new JacksonEncoder())
			.encoder(new FormEncoder())
			.decoder(new JacksonDecoder())
			.requestInterceptor(new HeadersInterceptor())
			.errorDecoder(new CustomErrorDecoder())
			.retryer(new MyRetryer(5))
			.exceptionPropagationPolicy(ExceptionPropagationPolicy.UNWRAP)
			.target(HelloService.class, "http://localhost:8080/");

可以看到我把之前的JacksonEncoder注释后,新配置了FormEncoder。但是我又希望同时使用这两种Encoder,OpenFeign对此也进行了支持,FormEncoder装饰JacksonEncoder,在FormEncoder类内部将另一个Ecoder对象作为类成员。

public class FormEncoder implements Encoder {
    private static final String CONTENT_TYPE_HEADER = "Content-Type";
    private static final Pattern CHARSET_PATTERN = Pattern.compile("(?<=charset=)([\\w\\-]+)");
    private final Encoder delegate;
    private final Map processors;

    public FormEncoder() {
        this(new Default());
    }

    public FormEncoder(Encoder delegate) {
        this.delegate = delegate;
        List list = Arrays.asList(new MultipartFormContentProcessor(delegate), new UrlencodedFormContentProcessor());
        this.processors = new HashMap(list.size(), 1.0F);
        Iterator var3 = list.iterator();

        while(var3.hasNext()) {
            ContentProcessor processor = (ContentProcessor)var3.next();
            this.processors.put(processor.getSupportedContentType(), processor);
        }

    }
    .....
}    

可以看到FormEncoder的无参构造函数也会创建默认的Encoder对象。我们可以使用以下方式进行配置:

.encoder(new FormEncoder(new JacksonEncoder()))

注意,在使用FormEncoder时,必须配置ContentType。FormEncoder支持两种类型:

application/x-www-form-urlencoded

在配置Header后,方法的参数我们可以使用@Param注解或者是参数类POJO

@RequestLine("POST /test/hello2")
@Headers("Content-Type: application/x-www-form-urlencoded")
ResultPojo hello2Post(@Param("name") String name);

@RequestLine("POST /test/hello2")
@Headers("Content-Type: application/x-www-form-urlencoded")
ResultPojo hello2Post2(ParamPojo paramPojo);

与之前相同,Pojo的变量名将被作为key。

multipart/form-data

在上传文件时需要使用该类型的Content-Type,OpenFeign也提供了几种使用方式:

@RequestLine("POST /test/file")
@Headers("Content-Type: multipart/form-data")
String uploadFile(@Param("file") File file);

@RequestLine("POST /test/bytedata")
@Headers("Content-Type: multipart/form-data")
String uploadByteData(@Param("bytedata") byte[] data);

@RequestLine("POST /test/formdata")
@Headers("Content-Type: multipart/form-data")
String uploadByFormData(@Param("file") FormData formData);


@RequestLine("POST /test/formpojo")
@Headers("Content-Type: multipart/form-data")
String uploadByPojo(FilePojo filePojo);

在上传文件时,文件可以支持几种不同的方法参数类型进行传输。

  • File 使用文件的扩展名来检测Content-Type
  • byte[] 字节数组将使用application/octet-stream作为Content-Type
  • FormData 将使用FormData设置的Content-Type和fileName
  • 自定义POJO

FormData

FormData是OpenFeign定义的请求参数类,该类有是三个成员变量,分别为contentType, fileName, byte[] data。

@SuppressFBWarnings({"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
public class FormData {
    private String contentType;
    private String fileName;
    private byte[] data;
    ...
}

在请求时会根据设置值作为Content-Type和fileName

FormData formData = new FormData("image/png", "filename.png", myDataAsByteArray);

服务端使用MultipartFile file作为接受参数,设置的fileName将作为文件的原始名称。

自定义POJO

通过自定义POJO,可以将所有的请求参数组合到一起,使用@FormProperty来设置表单参数名称。服务端使用Multipart file和相应的参数进行接收。

public class FilePojo {

    @FormProperty("id")
    String id;

    @FormProperty("filename")
    File file;

    public FilePojo() {
    }

    public FilePojo(String id, File file) {
        this.id = id;
        this.file = file;
    }
}
@RequestMapping("test/form-pojo")
public String uploadPojo(@RequestParam(value = "filename") MultipartFile file,
                         @RequestParam(value = "id") String id) {
    return id + file.getOriginalFilename();
}

至此,使用OpenFeign进行表单提交和文件上传的使用方式已经学习介绍完毕,更详细的内容请看官方文档。


源码地址:https://github.com/Edenwds/javaweb/tree/master/feigndemo

你可能感兴趣的:(Feign学习)