我正在使用Jersey学习JAX-RS(又名JSR-311)。我已经成功地创建了一个根资源,并正在摆弄参数:

@Path("/hello")
public class HelloWorldResource {

    @GET
    @Produces("text/html")
    public String get(
        @QueryParam("name") String name,
        @QueryParam("birthDate") Date birthDate) {

         // Return a greeting with the name and age
    }
}

这工作得很好,并处理当前区域内Date(String)构造函数能理解的任何格式(如YYYY/mm/dd和mm/dd/YYYY)。但如果我提供的值无效或无法理解,就会得到404响应。

例如:

GET /hello?name=Mark&birthDate=X

404 Not Found

如何自定义此行为?也许是一个不同的响应代码(可能是“400个坏请求”)?记录一个错误怎么样?也许可以在自定义报头中添加问题的描述(“糟糕的日期格式”)以帮助排除故障?或者返回一个完整的带有详细信息的Error响应,以及一个5xx状态码?


当前回答

如果你想打开浏览器登录窗口,就把@史蒂文拉文的答案作为一个扩展。我发现很难从过滤器中正确返回响应(MDN HTTP身份验证),如果用户还没有经过身份验证

这帮助我构建响应来强制浏览器登录,注意头的额外修改。这将把状态代码设置为401,并设置导致浏览器打开用户名/密码对话框的报头。

// The extended Exception class
public class NotLoggedInException extends WebApplicationException {
  public NotLoggedInException(String message) {
    super(Response.status(Response.Status.UNAUTHORIZED)
      .entity(message)
      .type(MediaType.TEXT_PLAIN)
      .header("WWW-Authenticate", "Basic realm=SecuredApp").build()); 
  }
}

// Usage in the Filter
if(headers.get("Authorization") == null) { throw new NotLoggedInException("Not logged in"); }

其他回答

@Provider
public class BadURIExceptionMapper implements ExceptionMapper<NotFoundException> {

public Response toResponse(NotFoundException exception){

    return Response.status(Response.Status.NOT_FOUND).
    entity(new ErrorResponse(exception.getClass().toString(),
                exception.getMessage()) ).
    build();
}
}

创建类之上。这将处理404 (NotFoundException),在toResponse方法中,您可以给出自定义响应。类似地,还有ParamException等,你需要映射它们来提供定制的响应。

一个明显的解决方案:采用字符串,转换为日期自己。这样你就可以定义你想要的格式,捕捉异常并重新抛出或自定义发送的错误。 对于解析,SimpleDateFormat应该可以正常工作。

我相信也有一些方法可以为数据类型钩子处理程序,但是在这种情况下,您可能只需要一点点简单的代码。

@QueryParam文档说

" The type T of the annotated parameter, field or property must either: 1) Be a primitive type 2) Have a constructor that accepts a single String argument 3) Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String)) 4) Have a registered implementation of javax.ws.rs.ext.ParamConverterProvider JAX-RS extension SPI that returns a javax.ws.rs.ext.ParamConverter instance capable of a "from string" conversion for the type. 5) Be List, Set or SortedSet, where T satisfies 2, 3 or 4 above. The resulting collection is read-only. "

如果你想控制String形式的查询参数不能转换为你的T类型时给用户的响应,你可以抛出WebApplicationException。Dropwizard附带以下*Param类,您可以根据需要使用。

布里帕拉姆,datparam, IntParam, LongParam, LocalDateParam, empidparam, UUIDParam。看到https://github.com/dropwizard/dropwizard/tree/master/dropwizard-jersey/src/main/java/io/dropwizard/jersey/params

如果你需要Joda DateTime,只需使用Dropwizard DateTimeParam。

如果上面的列表不适合您的需要,那么可以通过扩展AbstractParam来定义您自己的列表。重写解析方法。如果需要控制错误响应体,请重写错误方法。

Coda Hale关于这方面的好文章在http://codahale.com/what-makes-jersey-interesting-parameter-classes/

import io.dropwizard.jersey.params.AbstractParam;

import java.util.Date;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

public class DateParam extends AbstractParam<Date> {

    public DateParam(String input) {
        super(input);
    }

    @Override
    protected Date parse(String input) throws Exception {
        return new Date(input);
    }

    @Override
    protected Response error(String input, Exception e) {
        // customize response body if you like here by specifying entity
        return Response.status(Status.BAD_REQUEST).build();
    }
}

Date(String arg)构造函数已弃用。如果你使用Java 8,我会使用Java 8日期类。否则建议使用joda date时间。

Jersey在解组参数失败时抛出com.sun.jersey.api.ParamException异常,因此一个解决方案是创建一个ExceptionMapper来处理这些类型的异常:

@Provider
public class ParamExceptionMapper implements ExceptionMapper<ParamException> {
    @Override
    public Response toResponse(ParamException exception) {
        return Response.status(Status.BAD_REQUEST).entity(exception.getParameterName() + " incorrect type").build();
    }
}

如果你想打开浏览器登录窗口,就把@史蒂文拉文的答案作为一个扩展。我发现很难从过滤器中正确返回响应(MDN HTTP身份验证),如果用户还没有经过身份验证

这帮助我构建响应来强制浏览器登录,注意头的额外修改。这将把状态代码设置为401,并设置导致浏览器打开用户名/密码对话框的报头。

// The extended Exception class
public class NotLoggedInException extends WebApplicationException {
  public NotLoggedInException(String message) {
    super(Response.status(Response.Status.UNAUTHORIZED)
      .entity(message)
      .type(MediaType.TEXT_PLAIN)
      .header("WWW-Authenticate", "Basic realm=SecuredApp").build()); 
  }
}

// Usage in the Filter
if(headers.get("Authorization") == null) { throw new NotLoggedInException("Not logged in"); }