3

我有一个现有的 Jersey webservice 方法,它通过 Http POST 方法接受许多参数,该方法旨在处理标准表单数据,内容类型为 application/x-www-form-urlencoded;这些参数之一是字符串列表。下面是我拥有的方法签名的示例。

@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response createItem(
        @FormParam("p1") long p1,
        @FormParam("p2") String p2,
        @FormParam("p3") List<String> p3,
        @FormParam("p4") String p4,
        @Context UriInfo uriInfo
) throws SQLException {

这工作正常,当多个 p3 参数在 List 中传递时,Jersey 会正确生成并传递到方法中。

我现在需要制作此方法的替代版本,该版本将接受多部分请求,以便文件也可以与现有参数一起上传。所以我创建了一个非常相似的方法签名来使用多部分请求,示例如下所示。

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response createItemWithFile(
        @FormDataParam("p1") long p1,
        @FormDataParam("p2") String p2,
        @FormDataParam("p3") List<String> p3,
        @FormDataParam("p4") String p4,
        @FormDataParam("file") InputStream inputStream,
        @Context UriInfo uriInfo
) throws SQLException {

我将 FormParam 注释更改为 FormDataParam,因为我相信在使用多部分数据时需要这样做。我一直在尝试使用 RESTAssured 从 JUnit 测试中调用此方法来进行调用(与对原始方法所做的相同),但出现以下错误。

java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)

在 Jersey 代码中放置了一些断点,在堆栈跟踪中标识的一些点上,它似乎已经确定了要调用的正确方法,但是在它试图传递给它的参数列表中,省略了 p3 .

在处理多部分数据时,为了支持接受 List 作为输入,是否需要做一些不同的事情?鉴于这是一个可选参数,我希望无论如何都应该可以省略它,原始方法就是这种情况。

测试中用于调用该方法的 RESTAssured 代码如下。

Response response = given()                    
                .header("my_header", "xyz")
                .param("p1", "8000040")
                .param("p2", "sample string") 
                .param("p3", "first_value")
                .param("p4", "abcde")
                .multiPart("file", myFile1, inputStream)
                .expect()

在 RESTAssured 测试代码中使用 formParam 代替 param 时,我也尝试过,但得到相同的结果。

在此先感谢,任何帮助将不胜感激。

4

2 回答 2

3

浏览了更多的球衣代码后,我的结论是,在使用多部分时,我的方法中不能有 List 类型的参数。在过程中的某个时刻,Jersey 循环遍历方法上的每个参数,找到一个 Injectable 来读取每个参数的值(抱歉,这可能不是一个很好的解释,但我已经尽可能多地调试了),在 com.sun 类中getInjectables 方法中的 .jersey.multipart.impl.FormDataMultiPartDispatchProvider 是以下代码:

 private List<Injectable> getInjectables(AbstractResourceMethod method) {
    List<Injectable> list = new ArrayList<Injectable>(method.getParameters().size());
    for (int i = 0; i < method.getParameters().size(); i++) {
        Parameter p = method.getParameters().get(i);
        if (Parameter.Source.ENTITY == p.getSource()) {
            if (FormDataMultiPart.class.isAssignableFrom(p.getParameterClass())) {
                list.add(new FormDataMultiPartInjectable());
            } else {
                list.add(null);
            }
        } else if (p.getAnnotation().annotationType() == FormDataParam.class) {
            if (Collection.class == p.getParameterClass() || List.class == p.getParameterClass()) {
                Class c = ReflectionHelper.getGenericClass(p.getParameterType());
                if (FormDataBodyPart.class == c) {
                    list.add(new ListFormDataBodyPartMultiPartInjectable(p.getSourceName()));
                } else if (FormDataContentDisposition.class == c) {
                    list.add(new ListFormDataContentDispositionMultiPartInjectable(p.getSourceName()));
                }
            } else if (FormDataBodyPart.class == p.getParameterClass()) {
                list.add(new FormDataBodyPartMultiPartInjectable(p.getSourceName()));
            } else if (FormDataContentDisposition.class == p.getParameterClass()) {
                list.add(new FormDataContentDispositionMultiPartInjectable(p.getSourceName()));
            } else {
                list.add(new FormDataMultiPartParamInjectable(p));
            }
        } else {
            Injectable injectable = getInjectableProviderContext().getInjectable(p, ComponentScope.PerRequest);
            list.add(injectable);
        }
    }
    return list;
}

因此,当它看到参数类型是 List 或 Collection 时,它会在泛型类型不是 FormDataBodyPart 或 FormDataContentDisposition 的情况下忽略它。

为了解决这个问题,我刚刚更改了我的方法,以接受 p3 的逗号分隔字符串来代替列表。

于 2012-06-18T15:32:28.467 回答
0

我遇到了另一种解决方案,它可能比必须手动处理列表的逗号分隔版本等更好(更简单)。迟来的发布是为了帮助其他找到这篇文章的人。

更改 multipart 参数:

@FormDataParam("p3") List<String> p3,

@FormDataParam("p3") List<FormDataBodyPart> p3,

然后你在 P3 中有你的列表,你可以在其中FormDataBodyPart使用getValue().

来源:接收阵列-来自-form-elements-with-jersey

于 2019-01-22T02:37:19.797 回答