【问题标题】:sending List/Map as POST parameter jersey发送 List/Map 作为 POST 参数球衣
【发布时间】:2011-12-07 10:11:58
【问题描述】:

我想将 HashMap 对象作为 POST 变量发送到 ReST 资源。我使用Form 类来发送对象。客户端代码:

public static void main(String[] args)
    {
        ClientConfig config = new DefaultClientConfig();
        Client client = Client.create(config);
        WebResource service = client.resource(getBaseURI());

        HashMap<String, String> hashmap = new HashMap<String, String>();
        hashmap.put("Key1", "value1");
        hashmap.put("Key2", "value2");
        Form form = new Form();

        form.add("data1", hashmap);

        ClientResponse response = service.path("hello2").path("hello2").type(MediaType.APPLICATION_FORM_URLENCODED).post(ClientResponse.class, form);
        @SuppressWarnings("unchecked")
        MultivaluedMap<String, String> map = response.getEntity(MultivaluedMap.class);
        System.out.println(map.get("response").get(0));
        System.out.println(map.get("response2"));
    }

REST资源如下:

@Path("/hello2")
public class FormResource
{
    @Context
    UriInfo uriInfo;
    @Context
    Request request;

    public FormResource()
    {
    }

    public FormResource(UriInfo uriInfo, Request request)// , String data1)
    {
        this.uriInfo = uriInfo;
        this.request = request;
    }

    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public MultivaluedMap<String, String> newProj(@FormParam("data1") HashMap<String, String> postVarMap, @Context HttpServletResponse response)
    {

        System.out.println(postVarMap);
        MultivaluedMap<String, String> hash = new MultivaluedMapImpl();
        hash.add("response", "response1");
        hash.add("response", "response2");
        hash.add("response2", "fbshabfsdb");
        URI uri = uriInfo.getAbsolutePathBuilder().build();
        Response.created(uri).build();
        return hash;
    }

}

我在 Tomcat 6.0 日志中得到以下异常

Dec 7, 2011 3:38:39 PM org.apache.catalina.core.StandardContext reload
INFO: Reloading Context with name [/JerCDemo] has started
Dec 7, 2011 3:38:40 PM com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
  com.reflexis.nbe.jersey
Dec 7, 2011 3:38:40 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
  class com.reflexis.nbe.jersey.FormResource
Dec 7, 2011 3:38:40 PM com.sun.jersey.api.core.ScanningResourceConfig init
INFO: No provider classes found.
Dec 7, 2011 3:38:40 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.9.1 09/14/2011 02:05 PM'
Dec 7, 2011 3:38:40 PM com.sun.jersey.spi.inject.Errors processErrorMessages
SEVERE: The following errors and warnings have been detected with resource and/or provider classes:
  SEVERE: Missing dependency for method public javax.ws.rs.core.MultivaluedMap com.reflexis.nbe.jersey.FormResource.newProj(java.util.HashMap,javax.servlet.http.HttpServletResponse) at parameter at index 0
  SEVERE: Missing dependency for method public javax.ws.rs.core.MultivaluedMap com.reflexis.nbe.jersey.FormResource.newProj(java.util.HashMap,javax.servlet.http.HttpServletResponse) at parameter at index 0
  SEVERE: Method, public javax.ws.rs.core.MultivaluedMap com.reflexis.nbe.jersey.FormResource.newProj(java.util.HashMap,javax.servlet.http.HttpServletResponse), annotated with POST of resource, class com.reflexis.nbe.jersey.FormResource, is not recognized as valid resource method.
Dec 7, 2011 3:38:40 PM org.apache.catalina.core.ApplicationContext log
SEVERE: StandardWrapper.Throwable
com.sun.jersey.spi.inject.Errors$ErrorMessagesException
    at com.sun.jersey.spi.inject.Errors.processErrorMessages(Errors.java:170)
    at com.sun.jersey.spi.inject.Errors.postProcess(Errors.java:136)
    at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:199)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:771)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:766)
    at com.sun.jersey.spi.container.servlet.ServletContainer.initiate(ServletContainer.java:488)
    at com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.initiate(ServletContainer.java:318)
    at com.sun.jersey.spi.container.servlet.WebComponent.load(WebComponent.java:609)
    at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:210)
    at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:373)
    at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:556)
    at javax.servlet.GenericServlet.init(GenericServlet.java:212)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1173)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:993)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4420)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4733)
    at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3460)
    at org.apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.java:426)
    at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1357)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1649)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1658)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1658)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1638)
    at java.lang.Thread.run(Thread.java:619)
Dec 7, 2011 3:38:40 PM org.apache.catalina.core.StandardContext loadOnStartup
SEVERE: Servlet /JerCDemo threw load() exception
com.sun.jersey.spi.inject.Errors$ErrorMessagesException
    at com.sun.jersey.spi.inject.Errors.processErrorMessages(Errors.java:170)
    at com.sun.jersey.spi.inject.Errors.postProcess(Errors.java:136)
    at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:199)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:771)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:766)
    at com.sun.jersey.spi.container.servlet.ServletContainer.initiate(ServletContainer.java:488)
    at com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.initiate(ServletContainer.java:318)
    at com.sun.jersey.spi.container.servlet.WebComponent.load(WebComponent.java:609)
    at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:210)
    at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:373)
    at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:556)
    at javax.servlet.GenericServlet.init(GenericServlet.java:212)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1173)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:993)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4420)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4733)
    at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3460)
    at org.apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.java:426)
    at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1357)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1649)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1658)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1658)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1638)
    at java.lang.Thread.run(Thread.java:619)

我写的客户端代码正确吗? 还有其他方法可以将 HashMap 对象作为 POST 变量发送吗?

【问题讨论】:

    标签: java jersey


    【解决方案1】:

    只是为了澄清一下。 MultivaluedMap&lt;String, String&gt; 用于获取表单参数的一般映射,例如通过 POST HTTP 请求提交给您的服务的参数。它应该是这样使用的:

       @POST
       @Consumes("application/x-www-form-urlencoded")
       public void post(MultivaluedMap<String, String> formParams) {
         // Store the message
       }
    

    但是,当您的客户端应用程序需要为您的 REST 服务提供某种数据时(在您的情况下,HashMap 包含我想很多重要信息)它会先将其序列化为 XML,然后将其发送到然后将反序列化并使用它的服务。不幸的是,Jersey 无法自动编组/取消编组 HashMaps,所以如果你只是在 newProj 方法中提供了 HashMap 参数,你会得到一个异常。

    那么如何将 HashMap 发送到您的服务?好吧,关键是 JAXB @XmlRootElement 和自定义 XmlAdapter :-)

    首先,您需要为地图编写自己的包装器。包装器将使用 @XmlRootElement 注释

    @XmlRootElement
    public class MyHashMapObject<T, U> {
        private Map<T, U> mapProperty;
    
        public MyHashMapObject() {
            mapProperty = new HashMap<T, U>();
        }
    
        @XmlJavaTypeAdapter(MapAdapter.class) // NOTE: Our custom XmlAdaper
        public Map<T, U> getMapProperty() {
            return mapProperty;
        }
    
        public void setMapProperty(Map<T, U> map) {
            this.mapProperty = map;
        }
    }
    

    然后您需要定义“启用 JAXB”的地图元素:

    public class MapElement {
        @XmlElement
        public String key;
        @XmlElement
        public String value;
    
        private MapElement() {
        }
    
        public MapElement(String key, String value) {
            this.key = key;
            this.value = value;
        }
    }
    

    最后定义您的自定义 XmlAdapter:

    public class MapAdapter extends XmlAdapter<MapElement[], Map<String, String>> {
        public MapElement[] marshal(Map<String, String> arg0) throws Exception {
            MapElement[] mapElements = new MapElement[arg0.size()];
            int i = 0;
            for (Map.Entry<String, String> entry : arg0.entrySet())
                mapElements[i++] = new MapElement(entry.getKey(), entry.getValue());
    
            return mapElements;
        }
    
        public Map<String, String> unmarshal(MapElement[] arg0) throws Exception {
            Map<String, String> r = new HashMap<String, String>();
            for (MapElement mapelement : arg0)
                r.put(mapelement.key, mapelement.value);
            return r;
        }
    }
    

    一旦你准备好了所有这些(它必须被你的服务和客户端使用,所以把它放到某个 shard jar 中),你可以像这样定义你的服务:

    @Path("/hello")
    public class FormResource
    {
        //@GET
        @POST
        @Produces(MediaType.APPLICATION_XML)
        @Consumes(MediaType.APPLICATION_XML)
        public MyHashMapObject<String, String> post(
                    MyHashMapObject<String, String> anotherMap) {
    
            anotherMap.getMapProperty().put("e", "10");
            anotherMap.getMapProperty().put("f", "11");
            anotherMap.getMapProperty().put("g", "12");
    
            return anotherMap;
        }
    }
    

    你们现在都准备好了。你的客户应该是这样的:

       public class Test {  
          public static void main(String[] args) {
                ClientConfig config = new DefaultClientConfig();
                Client client = Client.create(config);
                WebResource service = client.resource(getBaseURI());
    
                // Now do the MAP stuff
                MyHashMapObject<String, String> map = new MyHashMapObject<String, String>();
                map.getMapProperty().put("a", "1");
                map.getMapProperty().put("b", "2");
    
                ClientResponse response = service.path("rest").path("hello2")
                    .type(MediaType.APPLICATION_XML)
                    .accept(MediaType.APPLICATION_XML)
                    .post(ClientResponse.class, map);
    
                Map<String, String> myMap = response.getEntity(MyHashMapObject.class).getMapProperty();     
                for(Map.Entry<String, String> entry : myMap.entrySet())
                    System.out.format("Key: %s, Value: %s\n", entry.getKey(), entry.getValue());
    
            }
    
            private static URI getBaseURI() {
                return UriBuilder.fromUri(
                        "http://localhost:8080/org.nowaq.jersey.first").build();
            }
        }
    

    现在您可以轻松地将您的 HashMap&lt;String, String&gt; 传递给您的 REST 服务。您还可以使实现更加通用。希望这会有所帮助。

    【讨论】:

    • 这适用于文件上传吗? (是否可以解决here问题中的问题?)
    • 这么复杂的一个:-(
    【解决方案2】:

    您可以在 javascript 中使用 JSON.stringify(myMap),从而将字符串化映射作为表单参数传递。

    在 java 中,您将字符串解析回如下映射:

        @Path("doStuff")
        @POST
        @Produces(MediaType.APPLICATION_JSON)
        public void doStuff(@FormParam("mapAsJson") String mapAsJson) throws JsonParseException, JsonMappingException, IOException {
            @SuppressWarnings("unchecked")
            HashMap<String,String> mapFromJson = (HashMap<String,String>)new ObjectMapper().readValue(mapAsJson, HashMap.class);
            //add your processing 
        }   
    

    【讨论】:

      【解决方案3】:

      将 Map 作为 POST 请求正文发送

      @POST
      @Produces("application/json")
      @Consumes("application/json")
      @Path("/sendUser")
      public Response sendUser(Map<String,String> usersMap) {
          String name = usersMap.get("Name");
          // first check for existing key
          String family = usersMap.get("Family");
          String phone = usersMap.get("Phone");
          String mobile = usersMap.get("Mobile");
          return Response.ok("Get user attributes successfully !").build();
      }
      

      从 POST 获取地图响应

      @POST
      @Produces("application/json")
      @Consumes("application/json")
      @Path("/getUser")
      public Response getUser(String searchInputJsonString) {
          Map<String,String> usersMap = new HashMap<>();
          usersMap.put("Name","Johm");
          usersMap.put("Family","W.R.Klein");
          usersMap.put("Phone","87540255");
          usersMap.put("Mobile", "112458033");
          return Response.ok(usersMap).build();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多