Jersey 2.27-在使用ExceptionMapper进行错误处理的情况下,不要接收JSON



凭证输入表单的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;
}

}

异常映射器

@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对象,这里是空括号{}。

为什么?

在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的一部分。您应该使用Responsegetter方法,并选择要设置的数据。

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);
}
}
  • 更改库jersy-media-json-joskson,而将库放入jackson-jaxrs-json提供程序

  • 错误详细信息类必须具有所有的setter和getter。

@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。

如果你知道如何做得更好,请在这里写

在此处输入图像描述

相关内容

最新更新