4

对于我的 REST 服务中的订购过程,我必须将“文章”列表从客户端发送到服务器。这些物品对象是自制的实体类型。我已经发现发送 STRING 或 INTEGER 对象列表确实有效,通过@FormParam 发送。

但是,一旦我尝试发送我自己的对象列表(甚至只有一个对象),我总是会收到HTTP 400 错误 "Bad Request"

我尝试了与下面相同的代码(仅更改了 form.add() 的参数和服务器方法的参数)并成功地 postet 字符串、整数和字符串列表。它只会使发送自己的对象类型出现问题。
日志记录告诉我未达到服务器方法。该过程之前的某个地方被破坏了。

我还尝试使用代理(Apache JMeter)来获取请求。这里它说参数kunde包含 value entities.Kunde%40af8358。所以我猜这个对象没有彻底(或根本没有)序列化。但是在响应中将这种对象从服务器发送到客户端工作正常——这里 XML 序列化没有问题。

可能是什么原因?是否可能无法通过 POST 发送自己的类型?
(PS:Kunde我的示例中的类型是可序列化的,并带有注释@XmlRootElement。)

预先感谢您的帮助!
亚娜

注意:我使用的是 SAP Netweaver AS。但到目前为止,它的行为与其他所有 Java AS 一样,所以我认为这不会是原因。其他所有 REST 操作都可以正常工作,即使 POST 没有自己的实体。

另外:我正在使用 JERSEY 库。


我在服务器端的代码:

@Path("/test")
    @POST
    @Produces(MediaType.TEXT_XML)
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)    
    public String test(
        @FormParam("kunde") Kunde kunde) {    

        return "The name of the customer is: "
           +kunde.getVorname()+" "+kunde.getNachname();        
    }

我在客户端的代码(该方法在会话 Bean 中):

public String  test() {

    Kunde kunde = new Kunde();
    kunde.setNachname("Müller");
    kunde.setVorname("Kurt");

    Form form = new Form();
    form.add("kunde", kunde);       

    return service
        .path("test")
        .type(MediaType.APPLICATION_FORM_URLENCODED)
        .accept(MediaType.TEXT_XML)
        .post(String.class, form);
}

服务是这样构建的:

com.sun.jersey.api.client.Client;
com.sun.jersey.api.client.WebResource;
com.sun.jersey.api.client.config.ClientConfig;
com.sun.jersey.api.client.config.DefaultClientConfig;

ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
service = client.resource(UriBuilder.fromUri("<service-url>").build());
4

1 回答 1

2

由于没有正确传输实体“Kunde”的新信息,我找到了一个
解决方案

我明确地将实体类转换为 XML/JSON(任何一种方式都有效)并将 XML/JSON 作为字符串放入表单中。在服务器端,我将 XML/JSON 字符串转换回实体,这很有效。
(似乎不可能传输不是字符串或整数的对象

希望这将帮助所有面临相同问题的人通过 REST 从客户端传输对象到服务器。
发送XML/JSON 转换的对象列表仍有待测试。我很快就会在此处添加结果。

您好,感谢 chrylis 的评论和提示。
亚娜


这是解决方案的代码,但为了简短起见,它只是新部分。

1)XML解决方案:

在客户端将实体更改为 XML 字符串:

...
OutputStream out = new ByteArrayOutputStream();

JAXBContext context = JAXBContext.newInstance(Kunde.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(kunde, out);
out.close();

Form form = new Form();
form.add("entity", out.toString());
...

将 XML 转换回服务器端的对象:

...
public String test(
    @FormParam("entity") String entityString) {      

    InputStream inputStream = new ByteArrayInputStream(entityString.getBytes());        
    Kunde kunde = JAXB.unmarshal(inputStream, Kunde.class);       

    return "Der Name des Kunden ist: "+kunde.getVorname()+" "+kunde.getNachname();
}


2)JSON解决方案:

在客户端将实体更改为 JSON 字符串:

...
OutputStream out = new ByteArrayOutputStream();

ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(out, kunde);
out.close();

Form form = new Form();
form.add("entity", out.toString());
...

用于将 JSON 字符串转换回服务器端的对象:

...
public String test(
    @FormParam("entity") String entityString) {      

    InputStream inputStream = new ByteArrayInputStream(entityString.getBytes());        
    Kunde kunde = new ObjectMapper().read((inputStream, Kunde.class));       

    return "Der Name des Kunden ist: "+kunde.getVorname()+" "+kunde.getNachname();
}

JAXB、JAXBContext、Marshaller 等类来自 package javax.xml.bind.*。类 ObjectMapper 来自 package org.codehaus.jackson.map.*

PS:因为现在传输纯字符串,你也可以使用@QueryParam. 但我不建议这样做,因为您会将整个 XML 作为 URL 中的文本字符串传输。也一样@PathParam

我推荐 JSON,因为格式比 XML 格式更纤细,而纤细是 REST 的目标。

于 2013-09-10T09:27:01.227 回答