我正在编写一个REST web应用程序(NetBeans 6.9, JAX-RS, TopLink Essentials),并试图返回JSON和HTTP状态代码。我已经准备好了代码,并在从客户端调用HTTP GET方法时返回JSON。从本质上讲:
@Path("get/id")
@GET
@Produces("application/json")
public M_機械 getMachineToUpdate(@PathParam("id") String id) {
// some code to return JSON ...
return myJson;
}
但是我还想返回一个HTTP状态码(500、200、204等)以及JSON数据。
我尝试使用HttpServletResponse:
response.sendError("error message", 500);
但这让浏览器认为这是一个“真正的”500,所以输出的网页是一个普通的HTTP 500错误页面。
我想返回一个HTTP状态代码,以便我的客户端JavaScript可以处理一些依赖于它的逻辑(例如,在HTML页面上显示错误代码和消息)。这是可能的还是HTTP状态码不应该用于这样的事情?
我使用jersey 2.0的消息体读取器和写入器。我有我的方法返回类型作为一个特定的实体,这也用于实现的消息体作者和我返回相同的pojo,一个SkuListDTO。
@ get
@Consumes({“application / xml”、“application / json "})
与@({“application / xml”、“application / json "})
@ path (" / skuResync”)
public SkuResultListDTO getSkuData()
....
return SkuResultListDTO;
我所改变的是这个,我离开作家实现单独和它仍然工作。
public Response getSkuData()
...
return Response.status(Response.Status.FORBIDDEN).entity(dfCoreResultListDTO).build();
使用Microprofile OpenAPI扩展Nthalk的答案,您可以使用@APIResponse注释将返回代码与您的文档对齐。
这允许标记JAX-RS方法
@GET
@APIResponse(responseCode = "204")
public Resource getResource(ResourceRequest request)
您可以使用ContainerResponseFilter解析这个标准化注释
@Provider
public class StatusFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
if (responseContext.getStatus() == 200) {
for (final var annotation : responseContext.getEntityAnnotations()) {
if (annotation instanceof APIResponse response) {
final var rawCode = response.responseCode();
final var statusCode = Integer.parseInt(rawCode);
responseContext.setStatus(statusCode);
}
}
}
}
}
当您在方法上添加多个注释时,就会出现警告
@APIResponse(responseCode = "201", description = "first use case")
@APIResponse(responseCode = "204", description = "because you can")
public Resource getResource(ResourceRequest request)
如果您希望保持资源层的响应对象干净,那么我建议您使用@NameBinding和绑定到ContainerResponseFilter的实现。
下面是注释的主要内容:
package my.webservice.annotations.status;
import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Status {
int CREATED = 201;
int value();
}
这是过滤器的核心部分:
package my.webservice.interceptors.status;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
@Provider
public class StatusFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
if (containerResponseContext.getStatus() == 200) {
for (Annotation annotation : containerResponseContext.getEntityAnnotations()) {
if(annotation instanceof Status){
containerResponseContext.setStatus(((Status) annotation).value());
break;
}
}
}
}
}
然后你的资源的实现就变成了:
package my.webservice.resources;
import my.webservice.annotations.status.StatusCreated;
import javax.ws.rs.*;
@Path("/my-resource-path")
public class MyResource{
@POST
@Status(Status.CREATED)
public boolean create(){
return true;
}
}
我发现用重复的代码构建json消息非常有用,就像这样:
@POST
@Consumes("application/json")
@Produces("application/json")
public Response authUser(JsonObject authData) {
String email = authData.getString("email");
String password = authData.getString("password");
JSONObject json = new JSONObject();
if (email.equalsIgnoreCase(user.getEmail()) && password.equalsIgnoreCase(user.getPassword())) {
json.put("status", "success");
json.put("code", Response.Status.OK.getStatusCode());
json.put("message", "User " + authData.getString("email") + " authenticated.");
return Response.ok(json.toString()).build();
} else {
json.put("status", "error");
json.put("code", Response.Status.NOT_FOUND.getStatusCode());
json.put("message", "User " + authData.getString("email") + " not found.");
return Response.status(Response.Status.NOT_FOUND).entity(json.toString()).build();
}
}