泽西岛2.27-使用ExceptionMapper处理错误时不接收JSON

时间:2018-12-14 06:49:14

标签: java rest jersey-2.0

用于凭证输入表的Bean组件

  public class UserCredentials {

    private String username;
    private String password;

    public UserCredentials() {
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

资源

@Path("auth")
   public class AuthenticationResource {
    @POST
    @Consumes( MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @PermitAll
    public Response authenticateUserName(UserCredentials credentials)  {

        EmployeeDao dao = new EmployeeDaoImpl();
        Employee email = dao.loadEmployeeByFieldStr("email", credentials.getUsername());

        if(email == null){
            throw new AccessDeniedException("Non found!");
        }

        credentials.setUsername(email.getEmail());
        Response response = Response.ok(credentials).build();

        return response;
    }

用于存储错误详细信息的模型

@JsonInclude( JsonInclude.Include.NON_NULL)
public class ApiErrorDetails {

    private Integer status;
    private String title;
    private String message;
    private String path;

    public ApiErrorDetails() {
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void setPath(String path) {
        this.path = path;
    }


}

ExceptionMapper

     @Provider
       public class AccessDeniedExceptionMapper 
              implements   ExceptionMapper<AccessDeniedException> {

        @Context
        private UriInfo uriInfo;

        @Override
        public Response toResponse(AccessDeniedException exception) {


            Response.Status status = Response.Status.UNAUTHORIZED; 

            ApiErrorDetails errorDetails = new ApiErrorDetails();

            errorDetails.setStatus(status.getStatusCode());
            errorDetails.setTitle(status.getReasonPhrase());
            errorDetails.setMessage(exception.getMessage());


            errorDetails.setPath(uriInfo.getAbsolutePath().getPath());

            Response.ResponseBuilder statusResponse = Response.status(status);
            Response.ResponseBuilder entity =  
                                        statusResponse.entity(errorDetails);
            Response.ResponseBuilder type = 
                              entity.type(MediaType.APPLICATION_JSON);
            Response response = type.build();

            return response;
        }
    }

注册配置

@ApplicationPath("/api/*")
public class JerseyConfig  extends ResourceConfig {

    public JerseyConfig() {

        packages("com.skillsimprover.restexamples.rest");
        register(AuthenticationResource.class);
        register(AccessDeniedExceptionMapper.class);
        register(AuthenticationExceptionMapper.class);
        register(DataNotFoundExceptionMapper.class);
    }
}

web.xml

<servlet>
        <servlet-name>Jersey REST Service</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.skillsimprover.restexamples.rest</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Jersey REST Service</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>

pom.xml

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>


    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>2.27</version>
    </dependency>


    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>${jersey.rest.version}</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.inject</groupId>
        <artifactId>jersey-hk2</artifactId>
        <version>2.26</version>     
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>${servlets.version}</version>
        <scope>provided</scope>
    </dependency>

</dependencies>

发生 RuntimeException 时,必须由实现 ExceptionMapper 接口的Jersey类拦截。

在调试过程中,我观察到响应的形成方式以及 AccessDeniedExceptionMapper 类中错误的详细信息。  但是在客户端,我只获得状态代码,状态代码已全部设置好,而不是带有错误详细信息的 JSON 对象,这里是空括号{}。

为什么?

2 个答案:

答案 0 :(得分:0)

在ExceptionMapper类中:

Response.Status status = Response.Status.UNAUTHORIZED; 

status是设置为Response.Status.UNAUTHORIZED的静态最终枚举变量。设置为单个值。您不能在像这样的值上使用get方法,因为它没有getter方法。我怀疑接下来的几行:

ApiErrorDetails errorDetails = new ApiErrorDetails();

            errorDetails.setStatus(status.getStatusCode());
            errorDetails.setTitle(status.getReasonPhrase());
            errorDetails.setMessage(exception.getMessage());

实际上什么也没做。 status.getStatusCode()status.getReasonPhrase()status.getMessage()不返回任何内容,因为上述getter方法不是Response.status类的一部分,而是ApiErrorDetails类的一部分。您应该使用Response getter方法并选择要设置的适当数据。

答案 1 :(得分:0)

                             Solution

资源

@Provider
@Produces( MediaType.APPLICATION_JSON )
@Consumes( MediaType.APPLICATION_JSON )
@Path("auth")
public class AuthenticationResource {

    @POST
    @PermitAll
    @Path("username")
    public Response authenticateUserName(UserCredentials credentials)  {

        EmployeeDao dao = new EmployeeDaoImpl();
        Employee email = dao.loadEmployeeByFieldStr("email", credentials.getUsername());

        if(email == null){
            throw new DataNotFoundException("An object not found!!!!!!");
        }

        credentials.setUsername(email.getEmail());
        Response response = Response.ok(credentials).build();

        return response;
    }
...

类例外

public class DataNotFoundException extends RuntimeException {

    public DataNotFoundException(String message) {
        super(message);
    }
}
  • 更改库 jersey-media-json-jackson ,而是将库 jackson-jaxrs-json-provider

  • 错误详细信息类必须具有所有设置方法和获取方法。

 @JsonInclude(JsonInclude.Include.NON_NULL)
 public class ApiErrorDetails {

    private Integer status;
    private String title;
    private String message;
    private String path;

    public ApiErrorDetails() {
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public Integer getStatus() {
        return status;
    }

    public String getTitle() {
        return title;
    }

    public String getMessage() {
        return message;
    }

    public String getPath() {
        return path;
    }
}

必须注册 JacksonJsonProvider.class

import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import org.glassfish.jersey.server.ResourceConfig;

import javax.ws.rs.ApplicationPath;

@ApplicationPath("api")
public class JerseyConfig  extends ResourceConfig {

    public JerseyConfig() {

        packages("com.skillsimprover.restexamples.rest");
        register(JacksonJsonProvider.class);

    }
}

请记住,必须将注释@ Provider 放在正在使用的自定义 ExceptionMappers 上。

@Provider
public class DataNotFoundExceptionMapper <E> implements ExceptionMapper<DataNotFoundException> {

    @Context
    private UriInfo uriInfo;

    @Override
    public Response toResponse(DataNotFoundException exception) {
        return getResponseException(Response.Status.NOT_FOUND, exception);
    }

    private <E> Response  getResponseException(Response.Status status, E exceptionSource ){

        Throwable exception = (Throwable) exceptionSource;

        ApiErrorDetails errorDetails = new ApiErrorDetails();

        errorDetails.setStatus(status.getStatusCode());
        errorDetails.setTitle(status.getReasonPhrase());
        errorDetails.setMessage(exception.getMessage());

        errorDetails.setPath(uriInfo.getAbsolutePath().getPath());

        Response.ResponseBuilder statusResponse = Response.status(status);
        Response.ResponseBuilder entity = statusResponse.entity(errorDetails);
        Response.ResponseBuilder type = entity.type(MediaType.APPLICATION_JSON);
        Response response = type.build();

        return response;
    }
}

例如,方法getResponseException()可以写入另一个类。 ClassUtils。

如果您知道如何做得更好,请在此处写下

enter image description here