Jersey method selection by query parameters

后端 未结 3 1209
渐次进展
渐次进展 2021-01-23 03:14

I need to implement a webservice that uses the first query parameter to identify the operation, i.e. the client call would be something like: http://localhost:8080/ws/oper

相关标签:
3条回答
  • 2021-01-23 03:52

    I think Claudio is correct - you could use Jersey, but you'd be on your own to handle the query parameters since it only matches on the path.

    You could inject a UriInfo and pull the query parameters out of that:

    @Path("/operation") 
    public class Operation {
    
        @Context
        protected UriInfo info;
    
        @GET 
        public String operation() {
            if (info.getQueryParameters().containsKey("create"))
                // do stuff
            else if (info.getQueryParameters().containsKey("info"))
                // other stuff
        } 
    

    }

    You could switch from Jersey to another framework. I believe that Spring can route to multiple methods based on query parameters.

    As you mentioned, perhaps you could write something that is a bit more standard and then remap the requests to that. For example, you could use a Servlet filter or a front end server like Apache httpd or nginx to modify the request.

    Thinking in terms of resources what is it that these operations are acting on? Customer accounts, movies, stock trades, etc. For arguments sake, let's say it's "Foo". You might go with something like this:

    @Path("/foo") 
    public class FooResource {
    
        @Context
        protected UriInfo info;
    
        @GET
        @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
        public Foo getById(@QueryParam("id") int id) {
             // get Foo by id
             Foo = ....
    
             // return an instance of Foo and let Jersey convert it to XML
             // or JSON depending on the "Accept" header that the client sent
             return foo;
        } 
    
        @POST
        @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
        public Response create(Foo instance)
        {
             // let Jersey deserialize the request body from JSON or XML.
             // save the instance however you want
             int id = fooService.save(instance);
    
             // return a 204 "created" with a "Location" header
             URI location = info.getAbsolutePathBuilder().path("{id}").build(id);
         return Response.created(location).build();
        }
    

    }

    It sounds like your URI structure is mandated by someone else so this might not be an option for you. If you do proceed with the current URI structure, there's one major pitfall that you should be aware of.

    According to the HTTP 1.1 spec, GET requests should be idempotent. It appears that your current design is creating new server side instances with GET requests. There's potential for breakage... intermediate proxies or web browsers could cache responses to your GET requests and prevent new instances from being created.

    0 讨论(0)
  • 2021-01-23 04:00

    I see this is already answered, but I had a similar problem and achieved a solution using sub-resources.

    package com.example.ws;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.QueryParam;
    
    @Path("/")
    public class Operation {
    
        @Path("/")
        public Object sub(@QueryParam("operation") String operation)
        {
           if ("info".equals(operation))
              return new InfoOp();
           if ("create".equals(operation))
              return new CreateOp();
           //handle via error code
        }
    
        public class InfoOp {
            @GET 
            public String info() {
                return "info";
            }
        }
    
        public class CreateOp {
            @GET 
            public String create(@QueryParam("name") String name) {
                return "create: " + name;
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-23 04:11

    I think method selection is based on the non parameter part of the URI. Can't you design this in a way the client invoke http://localhost:8080/ws/operation/info and http://localhost:8080/ws/operation/create?name=something instead?

    That would be easy to achieve:

    @Path("/operation")
    public class Operation {
    
        @GET 
        @Path("info")
        public String info() {
            return "info";
        }
    
        @GET 
        @Path("create")
        public String create(@QueryParam("name") String name) {
            return "create";
        }
    }
    
    0 讨论(0)
提交回复
热议问题