Как правильно обрабатывать пустой набор результатов с помощью Hibernate и Spring Boot

У меня есть приложение Spring, которое использует Hibernate и JPA Spring DataCrudRepository, Кажется, все работает правильно, если в базе данных есть данные, которые были запрошены. Однако, если есть запрос, который не возвращает результат,CrudRepository возвращаетсяnull и я получаюNullPointerException, Так напримерhttp://localhost:8080/api/id=3 если в базе данных есть строка с идентификатором 3, она работает нормально. Если нет строки с идентификатором 3, она завершается с:

произошла непредвиденная ошибка (тип = Внутренняя ошибка сервера, статус = 500)

На стороне клиента иNullPointerException на стороне сервера.

Как правильно обращаться с простым случаем запроса «Нет результатов»?

 Kevin Vasko10 июн. 2016 г., 23:02
Не могли бы вы уточнить свой подход?
 JB Nizet10 июн. 2016 г., 23:00
вернуть 404 Not Found.

Ответы на вопрос(2)

Ни один из методов поиска в весеннем хранилище не выдает исключение, если результаты не возвращаются. Все они возвращают нули. Поскольку вы получаете исключение нулевого указателя на стороне сервера, вы должны пытаться выполнить операцию с возвращаемым значением, не проверяя, является ли оно нулевым в первую очередь.

Решение Вопроса

Проверьте возвращаемое значение, если оно неnull, вернуть некоторое представление об этом как200 OK ответ. В противном случае вернуть404 Not Found, В конце концов, у вас будет такой контроллер:

@RequestMapping(...)
public ResponseEntity<?> getOne(...) {
    Something something = repository.findOne(...);
    if (something == null)
        return ResponseEntity.notFound().build();

    return ResponseEntity.ok(something);
}

Вы можете реорганизовать предыдущий код для включения Java 8Optional<T>, какДж. Б. Низет упоминается вКомментарии, В принципе,Optional<T> это просто контейнер, который может содержать или не содержать значение типаT, Вы можете использовать этот тип в качестве возвращаемого типа методов JPA Spring Data, например:

public interface SomethingRepository extends CrudRepository<Something, Long> {
    Optional<Something> findById(Long id);
}

Затем определите одно исключение для404 Not Found:

@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException {}

Если вы бросаете исключение типаNotFoundException в ваших контроллерах средство разрешения исключений Spring MVC перехватит это исключение и преобразует его в404 Not Found HTTP ответ.

Наконец, ваш контроллер будет выглядеть так:

@RequestMapping(...)
public Something getOne(...) {
    return repository.findById(id).orElseThrow(NotFoundException::new);
}

Для более подробного обсуждения:

Spring Data JPA'sOptional<T> служба поддержки,читай здесь.Средства разрешения исключений Spring MVC,читай здесь.Java 8Optional<T>, читай здесь.Лучшие практики ОТДЫХА, вы можете проверитьОТДЫХ на практике книга.
 Ali Dehghani10 июн. 2016 г., 23:26
@JBNizet Да, это отличная идея.
 Ali Dehghani10 июн. 2016 г., 23:49
@JBNizet Обновил ответ с вашим предложением. Спасибо
 JB Nizet10 июн. 2016 г., 23:25
Или вы можете сгенерировать исключение и добавить аннотацию для исключения@ResponseStatus(HttpStatus.NOT_FOUND), В сочетании с возможностью Spring-data-jpa возвращать пустой Optional вместо null, вы можете использовать:Something something = somethingRepository.findById(id).orElseThrow(NotFoundException::new);
 Kevin Vasko13 июн. 2016 г., 16:59
Спасибо, это сработало. Было бы лучше разместить "@ResponseStatus" и "@RequestMapping" на моем уровне контроллера или уровне сервисов?
 Ali Dehghani13 июн. 2016 г., 17:10
Лучше не выставлять специфичные для контроллера вещи на ваш сервисный уровень

Ваш ответ на вопрос