正如标题所示我有一个非常简单的问题,我在服务器上设置了两个端点,我能够对它们执行@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请求不能像上面那样工作。我在这里做错了什么?
答案 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中测试我的服务