Статьи

Обработка пользовательских исключений Jax-RS

Одной из приятных особенностей работы с JEE является то, что доступные компоненты действительно довольно стандартны. При использовании JAX-RS иногда необходимо контролировать, как исключения обрабатываются и передаются пользователю. Если выдается исключение, по умолчанию вы получаете ужасное исключение внутреннего сервера HTTP 500, которое раскрывает внутренние сбои вашего веб-сервиса.

Рассмотрим следующую суть: эта конечная точка будет использоваться для просмотра пользователя на основе идентификатора.

1
2
3
4
5
6
7
8
9
@Path("/users")
public interface UserWebService {
     
    @POST
    @Consumes({ MediaType.APPLICATION_JSON })
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    @Path("/{userId}")
    Response getUser(@PathParam("userId") String userId);
}

Теперь реализация этого интерфейса будет выглядеть примерно так, чтобы сделать работу осла по фактическому извлечению пользователя.

01
02
03
04
05
06
07
08
09
10
public final class UserWebServiceImpl implements UserWebService {
     
    @EJB
    private UserDao userDao;
     
    public Response getUser(final String userId) {
        final User user = userDao.getUser(userId);
        return Response.ok().entity(user).build();
    }
}

Это выглядит хорошо, но подумайте, если userDao делал какую-то бизнес-логику сущности, используя Query.getSingleResult, а пользователь с таким ID не существовал?

Согласно документации JEE6 API, вы получите NoResultException , что приведет к ошибке HTTP 500, выставляющей исключение вашего внутреннего сервера, что, безусловно, не должно видеть конечный пользователь. Нам нужно использовать обработку исключений Jax-RS!

Во-первых, нам нужен тупой объект исключения с соответствующим именем, который будет тем, что мы на самом деле бросим, ​​рассмотрим код ниже ..

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
public class UserWebServiceException extends Exception implements
    Serializable {
 
    private static final long serialVersionUID = 1169426381288170661L;
 
    public UserWebServiceException() {
        super();
    }
 
    public UserWebServiceException(String msg) {
        super(msg);
    }
 
    public UserWebServiceException(String msg, Exception e) {
        super(msg, e);
    }
}

Затем нам нужно изменить наш исходный код, чтобы учесть это исключение. Ниже я соответствующим образом изменил исходный UserWebService и соответствующую реализацию.

1
2
3
4
5
6
7
8
9
@Path("/users")
public interface UserWebService {
     
    @POST
    @Consumes({ MediaType.APPLICATION_JSON })
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    @Path("/{userId}")
    Response getUser(@PathParam("userId") String userId) throws UserWebServiceException;
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
public final class UserWebServiceImpl implements UserWebService {
     
    @EJB
    private UserDao userDao;
     
    public Response getUser(final String userId) throws UserWebServiceException {
        try {
            final User user = userDao.getUser(userId);
        } catch(NoResultException e) {
            throw new UserWebServiceException("User does not exist with id " + userId);
        }
        return Response.ok().entity(user).build();
    }
}

Теперь это вызовет соответствующее исключение, когда пользователь не может быть найден. Однако нам все еще нужно создать объект Handler, чтобы преобразовать это исключение в реальный ответ JSON, чтобы мы получили приятное дружеское сообщение об ошибке. Класс ниже обрабатывает это исключение и преобразует сообщение об ошибке в исключении в ответ JSON. Важная аннотация этого класса — аннотация @Provider .

01
02
03
04
05
06
07
08
09
10
11
@Provider
public final class UserWebServiceExceptionHandler implements
    ExceptionMapper<UserWebServiceException> {
 
    @Override
    public Response toResponse(final UserWebServiceException exception) {
        return Response.status(Status.BAD_REQUEST)
            .entity(new ErrorMessage(exception.getMessage())
            ).type(MediaType.APPLICATION_JSON).build();
    }  
}

Вы заметите, что мы создаем объект ErrorMessage для ответа от веб-службы. Это просто простой тупой объект для хранения сведений о фактической ошибке, которая будет передана в JSON.

01
02
03
04
05
06
07
08
09
10
11
public class ErrorMessage {
    private String error;
 
    public ErrorMessage(String error) {
        this.error = error;
    }
 
    public String getError() {
        return error;
    }
}

Последний шаг в сопоставлении нашего поставщика обработчика исключений с веб-приложением заключается в добавлении следующего в наш web.xml для нашего веб-приложения.

1
2
3
4
<context-param>
    <param-name>resteasy.providers</param-name>
    <param-value>uk.co.soa.rest.providers.UserWebServiceExceptionHandler</param-value>       
</context-param>

Теперь, когда мы вызываем эту конечную точку REST с несуществующим идентификатором пользователя (скажем, «DAG»), мы с радостью получим следующий ответ JSON, а не трассировку стека.

1
2
3
{
    "error": "User does not exist with id DAG"
}
Ссылка: Пользовательская обработка исключений Jax-RS от нашего партнера JCG Дэвида Грея из блога Code Mumble .