2

我的 RESTEasy 服务中有一个方法,我想同时用作@GET/ @POST,它的数据可能来自查询字符串和请求正文。

@GET
@POST
public String myMethod(@QueryParam("param1") @FormParam("param1") String param1,
                       @QueryParam("param2") @FormParam("param1") String param2) {
    // ...do things
}

但是,如果不执行以下操作,我还没有找到一种方法:

@GET
public String myMethod(@QueryParam("param1") String param1, @QueryParam("param2") String param2) {
    // ...do things
}

@POST
public String myMethod2(@FormParam("param1") String param1, @FormParam("param2") String param2) {
    return this.myMethod(param1, param2);
}

有谁知道如何使第一个示例工作,或者使用尽可能少的代码的另一种方法?

4

3 回答 3

6

引用RESTful Java with JAX-RS一书:

JAX-RS 定义了五个映射到特定 HTTP 操作的注解:

  • @javax.ws.rs.GET
  • @javax.ws.rs.PUT
  • @javax.ws.rs.POST
  • @javax.ws.rs.DELETE
  • @javax.ws.rs.HEAD

(...)
注释@GET指示 JAX-RS 运行时此 Java 方法将处理对 URI 的 HTTP GET 请求。您将使用前面描述的其他五个注释之一来绑定到不同的 HTTP 操作。不过需要注意的一点是,您只能为每个 Java 方法应用一个 HTTP 方法注释。如果您应用多个,则会发生部署错误。

(以上文字由 ​​RESTEasy 的创建者编写。)

而且,简而言之,由于 RESTEasy 符合 JAX-RS,您不能使用多个 HTTP 动词注释方法。

如果你不服气,看一下注解,@GET你会发现它只是一个元注解@HttpMethod

/**
 * Indicates that the annotated method responds to HTTP GET requests
 * @see HttpMethod
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod(HttpMethod.GET)
public @interface GET { 
}

如果您打开@HttpMethod,请检查 javadoc (使用多个注释注释的方法是错误的HttpMethod注释):

/**
 * Associates the name of a HTTP method with an annotation. A Java method annotated
 * with a runtime annotation that is itself annotated with this annotation will
 * be used to handle HTTP requests of the indicated HTTP method. It is an error
 * for a method to be annotated with more than one annotation that is annotated
 * with {@code HttpMethod}.
 *
 * @see GET
 * @see POST
 * @see PUT
 * @see DELETE
 * @see HEAD
 */
@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HttpMethod
{

所以,就是这样,你不能在同一种方法中同时拥有它们。


也就是说,如果你真的必须,你可以通过PreProcessInterceptor在 JAX-RS 方法之前调用的方法来实现这一点。

尽管如此,这种方式要复杂得多(因为您必须自己解析参数)并且可维护性要差得多(在拦截器处提供服务!?)。

底线,据我所知,您的解决方案是最佳的。

检查我在下面的测试中所说的内容:

public class QueryAndFormParamTest  {

    @Path("/")
    public static class InterceptedResource {
        @GET
        //@Path("/stuff") // uncomment this and it will not work
        public String otherService(@QueryParam("yadda") String name){
            return "Im never called in this example" + name;
        }
    }

    public static class MyInterceptor implements PreProcessInterceptor, AcceptedByMethod {
        @Override
        public boolean accept(Class declaring, Method method) {
            System.out.println("Accepted by method "+method.getName());
            // you can check if this interceptor should act on this method here
            return true; // it'll act everytime
        }

        @Override
        public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
                throws Failure, WebApplicationException {

            // parsing form parameters
            if (request.getHttpHeaders().getMediaType() != null && request.getHttpHeaders().getMediaType().isCompatible(MediaType.valueOf("application/x-www-form-urlencoded"))) {
                MultivaluedMap<String, String> formParameters = request.getFormParameters();
                if (formParameters != null) {
                    for (String key : formParameters.keySet()) {
                        System.out.println("[FORM] "+key + ": "+formParameters.get(key));
                    }
                }
            }

            // parsing query parameters
            MultivaluedMap<String, String> queryParameters = request.getUri().getQueryParameters();
            if (queryParameters != null)
            for (String key : queryParameters.keySet()) {
                System.out.println("[QUERY] "+key + ": "+queryParameters.get(key));
            }

            String responseText = "do something: " + request.getUri().getQueryParameters().getFirst("test");
            return new ServerResponse(responseText, 200, new Headers<Object>());
        }
    }

    @Test
    public void test() throws Exception {
        Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
        dispatcher.getProviderFactory().getServerPreProcessInterceptorRegistry().register(new MyInterceptor());
        dispatcher.getRegistry().addSingletonResource(new InterceptedResource());

        MockHttpRequest request = MockHttpRequest.get("/?test=someStuff");
        MockHttpResponse response = new MockHttpResponse();

        dispatcher.invoke(request, response);

        System.out.println(response.getContentAsString());
        Assert.assertEquals("do something: someStuff", response.getContentAsString());
    }
}
于 2013-05-10T15:42:33.953 回答
5

您不能拥有一个 REST 方法,该方法使用多个@GET, @POST, @PUT,注释进行@DELETE注释,因为这与 HTTP 规范相冲突。

此外,如果myMethod2只返回 的结果myMethod,您可以在应用程序中使用其中唯一的一个(例如,myMethod),因为基本上myMethod2只是从服务器读取检索数据,但不会更新任何内容。这意味着用 注释是不合适的@POST,因为它不会更新服务器上的任何内容。如果用 注释@POST,它仍然可以工作,但它不符合 HTTP 规范。

CRUD 操作和 HTTP 动词之间存在映射。在服务器上创建资源的情况下,您必须使用PUTorPOST并且在您希望从服务器读取某些资源的情况下,您应该使用GET. 所有案例如下:

Create = PUT with a new URI
         POST to a base URI returning a newly created URI
Read   = GET
Update = PUT with an existing URI
Delete = DELETE
于 2013-05-10T14:30:20.977 回答
1

For binding the multiple queryParam into single object we need add @Form as a arguments in response method. It works fine for us.

@GET    
@Path("/")  
@Produces("application/json")
@Consumes("application/json")

public Response search(@Form CatalogSearchRequest reqObject)      
{

System.out.println("Entered into service"+reqObject.getAttribute());


}

POJO CLASS should contain @QueryParam("") for every attributes
for example:

@QueryParam("pageSize")
public Integer pageSize;

@QueryParam("page")
public Integer page;

public Integer getPageSize() {
    return pageSize;
}

public void setPageSize(Integer pageSize) {
    this.pageSize = pageSize;
}

public Integer getPage() 
{
 return page;
}

public void setPage(Integer page)
{
    this.page = page;
}

regards,
Prasanna.

于 2013-09-26T12:08:01.327 回答