只有@GET请求适用于我的RESTFUL应用程序

时间:2016-03-27 19:15:10

标签: java web-services http jax-ws

正如标题所示我有一个非常简单的问题,我在服务器上设置了两个端点,我能够对它们执行@GET命令,但是@POST和@DELETE消息会定期返回404响应。我可能会遗漏一些明显的东西。

以下是我的POM依赖项:

    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>javax.ws.rs-api</artifactId>
        <version>2.0.1</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-common</artifactId>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-client</artifactId>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-grizzly2-http</artifactId>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.test-framework</groupId>
        <artifactId>jersey-test-framework-util</artifactId>
    </dependency>

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.4</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-bundle</artifactId>
        <type>pom</type>
    </dependency>

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.4</version>
    </dependency>

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

以下是我使用的示例界面:

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

/**
 * The interface shared to airport weather collection systems.
 *
 * @author code test administartor
 */
public interface TestEndpoint {

    /**
     * This works like a charm
     */
    @GET
    @Path("/ping")
    Response ping();

    /**
     * This does NOT work keeps throwing 404
     */
    @POST
    @Path("/weather/{iata}/{pointType}")
    Response updateWeather(@PathParam("iata") String iataCode,
                           @PathParam("pointType") String pointType,
                           String datapointJson);

    /**
     * This works like a charm
     */
    @GET
    @Path("/airports")
    @Produces(MediaType.APPLICATION_JSON)
    Response getAirports();

   /**
     * This works like a charm
     */
    @GET
    @Path("/airport/{iata}")
    @Produces(MediaType.APPLICATION_JSON)
    Response getAirport(@PathParam("iata") String iata);

    /**
     * This does NOT work keeps throwing 404
     */
    @POST
    @Path("/airport/{iata}/{lat}/{long}")
    Response addAirport(@PathParam("iata") String iata,
                        @PathParam("lat") String latString,
                        @PathParam("long") String longString);

    /**
     * This does NOT work keeps throwing 404
     */
    @DELETE
    @Path("/airport/{iata}")
    Response deleteAirport(@PathParam("iata") String iata);

    /**
     * This works like a charm
     */
    @GET
    @Path("/exit")
    Response exit();
}

此界面的实施:

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
import java.util.Set;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.stream.Collectors;


/**
 * A REST implementation of the WeatherCollector API. Accessible only to airport weather collection
 * sites via secure VPN.
 *
 * @author code test administrator
 */

@Path("/collect")
public class TestEndpointImpl implements TestEndpoint {
    public final static Logger LOGGER = Logger.getLogger(TestEndpointImpl .class.getName());

    /**
     * shared gson json to object factory
     */
    public final static Gson gson = new Gson();

    @Override
    public Response ping() {
        return Response.status(Response.Status.OK).entity("ready").build();
    }

    @Override
    public Response updateWeather(@PathParam("iata") String iataCode,
                                  @PathParam("pointType") String pointType,
                                  String datapointJson) {
        try {
            ....
            return Response.status(Response.Status.OK).build();
        } catch (JsonSyntaxException e) {
            LOGGER.severe(String.format("The given json input is not well formatted: %s", datapointJson));
            return Response.status(Response.Status.NOT_ACCEPTABLE).build();
        } catch (IllegalArgumentException e) {
            LOGGER.severe("Invalid arguments.");
            return Response.status(Response.Status.NOT_ACCEPTABLE).build();
        } catch (Exception e) {
            LOGGER.severe("Internal server error");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
        }
    }

    @Override
    public Response getAirports() {
        ....
        return Response.status(Response.Status.OK).entity(iatas).build();
    }

    @Override
    public Response getAirport(@PathParam("iata") String iata) {
        try {
           ....
        } catch (IllegalArgumentException ex) {
            LOGGER.warning("Invalid values submitted.");
            return Response.status(Response.Status.NOT_ACCEPTABLE).build();
        } catch (Exception e) {
            LOGGER.severe("Internal server error");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
        }
    }

    @Override
    public Response addAirport(@PathParam("iata") String iata,
                               @PathParam("lat") String latParam,
                               @PathParam("long") String longParam) {
        try {
           ....
            return Response.status(Response.Status.OK).build();
        } catch (IllegalArgumentException ex) {
            LOGGER.warning("Invalid values submitted.");
            return Response.status(Response.Status.NOT_ACCEPTABLE).build();
        } catch (Exception e) {
            LOGGER.severe("Internal server error");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
        }
    }

    @Override
    public Response deleteAirport(@PathParam("iata") String iata) {
        try {
            ....
            return Response.status(Response.Status.OK).build();
        } catch (IllegalArgumentException ex) {
            LOGGER.warning("Invalid values submitted.");
            return Response.status(Response.Status.NOT_ACCEPTABLE).build();
        } catch (Exception e) {
            LOGGER.severe("Internal server error");
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
        }
    }

    @Override
    public Response exit() {
        System.exit(0);
        return Response.noContent().build();
    }

}

运行服务器的服务器:

public static void main(String[] args) {
        try {
            System.out.println("Starting Weather App local testing server: " + BASE_URL);
            System.out.println("Not for production use");

            final ResourceConfig resourceConfig = new ResourceConfig();
            resourceConfig.register(TestEndpointImpl.class);
            final HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URL), resourceConfig, false);

            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                server.shutdownNow();
            }));

            HttpServerProbe probe = new HttpServerProbe.Adapter() {
                public void onRequestReceiveEvent(HttpServerFilter filter, Connection connection, Request request) {
                    System.out.println(request.getRequestURI());
                }
            };

            server.getServerConfiguration().getMonitoringConfig().getWebServerConfig().addProbes(probe);
            System.out.println(format("Weather Server started.\n url=%s\n", BASE_URL));
            server.start();

            // blocks until exit
            Thread.currentThread().join();
            server.shutdown();
        } catch (IOException | InterruptedException ex) {
            Logger.getLogger(TestServer.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

我的测试客户端

private static final String BASE_URI = "http://localhost:9090";

    /** end point to supply updates */
    private WebTarget collect;

    public TestClient() {
        Client client = ClientBuilder.newClient();
        collect = client.target(BASE_URI + "/collect");
    }

    public void pingCollect() {
        WebTarget path = collect.path("/ping");
        Response response = path.request().get();
        System.out.print("collect.ping: " + response.readEntity(String.class) + "\n");
    }

    public void delete(String iata) {
        WebTarget path = collect.path("/airport/" + iata);
        Response response = path.request().delete();
        System.out.println("Deleting airport result: " + response.getStatus());
    }

    public void populate(String pointType, int first, int last, int mean, int median, int count) {
        WebTarget path = collect.path("/weather/BOS/" + pointType);
        DataPoint dp = new DataPoint.Builder()
                .withFirst(first).withLast(last).withMean(mean).withMedian(median).withCount(count)
                .build();
        Response post = path.request().post(Entity.entity(dp, "application/json"));
    }

    public void exit() {
        try {
            collect.path("/exit").request().get();
        } catch (Throwable t) {
            // swallow
        }
    }

    public static void main(String[] args) {
        TestClientwc = new TestClient();
        wc.pingCollect();
        wc.populate("wind", 0, 10, 6, 4, 20);

        wc.delete("MMU");

        wc.exit();
        System.out.print("complete");
        System.exit(0);
    }
}

我抛弃了一个不同的客户端进行查询,但工作方式相同。 @GET请求没问题@POST / @DELETE请求不能像上面那样工作。我在这里做错了什么?

1 个答案:

答案 0 :(得分:4)

我认为注释必须在服务类上,而不是在接口上。这意味着您的接口上当前配置的注释需要移动到实现类TestEndpointImpl

此外,我可以建议以下内容:在您的客户端中,您将application / json指定为发布到服务的内容的mime类型。但是,在服务端,您需要@Consumes注释来注册为特定内容类型选择的方法。

作为奖励,您可以使用自动JSON到Java对象映射并提供POJO参数而不仅仅是String并手动解析JSON。

顺便说一下。我通常使用JBoss Webservice测试器或RESTClient Firefox https://addons.mozilla.org/en-US/firefox/addon/restclient/

在Eclipse中测试我的服务