Конечная точка Java REST для возврата любых столбцов базы данных

Допустим, у меня есть таблица postgres с именем Employee со следующими столбцами:

  • Я БЫ
  • Имя
  • Фамилия
  • Работа
  • Дата
  • Управляющий делами
  • отделение

Мне интересно иметь конечную точку REST, чтобы /employee/{ID} вернул всю информацию для этого конкретного сотрудника в формате JSON, но если я укажу /employee/{ID}/FirstName, то он вернет имя конкретного сотрудника только в формате JSON, /employee/{ID}/LastName вернет фамилию сотрудника в формате JSON. формат JSON и так далее. Есть ли хороший способ реализовать это вместо реализации конечной точки для доступа к каждому столбцу? Спасибо.

Не могли бы вы сделать это с одной конечной точкой, т.е. /employee/{id}/{attribute} и сопоставить attribute с именем столбца?

dave 25.02.2019 02:34

Я считаю, что это решение, которое я ищу. Но означает ли это также, что в моей функции конечной точки мне потребуется функция сопоставления, которая переходит от атрибута к извлечению столбцов? Я думаю, мой главный вопрос в том, что сейчас в базе данных 7 столбцов, и я могу определить их, как вы упомянули, но если в будущем будет добавлен 8-й столбец, возможно ли, что мы можем создать конечную точку теперь, чтобы нам не нужно было изменять код при добавлении нового столбца?

user1177054 25.02.2019 02:44

Когда я использую {attribute} в конечной точке, это подстановочный знак, который обычно реализуется с помощью PathVariable (или его эквивалента). Убедитесь, что любая библиотека, которую вы используете для REST/MVC, поддерживает это. Если это так, вам нужно будет написать свое сопоставление. Сопоставление нужно будет изменить, если вы добавите новый столбец, но ваша конечная точка этого не сделает.

dave 25.02.2019 02:50

Спасибо. Я считаю, что «сопоставление нужно будет изменить, если вы добавите новый столбец», это то, что я действительно хотел проверить.

user1177054 25.02.2019 03:02
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
750
3

Ответы 3

Простой способ решить эту проблему — использовать параметр запроса вместо запроса URL-адреса. Используя такой параметр, как fields, вы получите URL-адрес, подобный /employee/{id}?fields=FirstName,LastName. Используя приведенный ниже код, вы можете получить Map<String, Object>, который будет сериализован в JSON с вашими данными. Нравится:

@ResponseBody
public Map<String, Object> getPerson(@PathVariable("id") long id, @RequestParam("fields") String fields) throws Exception {
    return personService.getPersonFields(id, fields);
}

@Service
class PersonService {

    public Map<String, Object> getPersonFields(Long personId, String fields) throws Exception {
        final Person person = personRepository.findById(personId);
        if (person == null) {
            throw new Exception("Person does not exists!");
        }

        String[] fieldsArray = fields.split(",");
        Map<String, Field> personFields = Arrays.stream(person.getClass().getFields()).collect(Collectors.toMap(Field::getName, field -> field);

        Map<String, Object> personFieldsReturn = new HashMap<>();
        for (String field : fieldsArray) {
            if (personFields.containsKey(field)) {
                personFields.get(field).setAccessible(true);
                personFieldsReturn.put(field, personFields.get(field).get(person));
                personFields.get(field).setAccessible(false);
            }
        }

        return personFieldsReturn;
    }

}

Однако это не очень хорошее решение. Но это должно работать.

Это рискованное решение — вам лучше не раскрывать имена столбцов в вашем API.

dave 25.02.2019 02:52

Что ж, используйте его для сопоставления вашего DTO с контроллером вместо сопоставления сущности со службой. Это та же логика.

R. Karlus 25.02.2019 02:53

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

R. Karlus 25.02.2019 02:54

Я вижу вашу точку зрения. Однако столбцы (или поля) базы данных относятся к уровню доступа к данным и не должны отображаться в контроллерах. Любое сопоставление атрибутов объекта (часть модели) с концепциями БД относится к уровню доступа к данным.

dave 25.02.2019 02:56

Итак, как упоминал @dave в комментарии, у вас может быть конечная точка REST /employee/{ID}/{column}, и в вашем контроллере у вас будет сопоставление между значением аргумента {column} и фактическим именем столбца в базе данных. Если вы не хотите повторно развертывать свое приложение при изменении сопоставления, вы можете поместить его в отдельный файл свойств на сервере за пределами вашего jar/war, а также добавить дополнительную конечную точку либо для перезагрузки файла формы сопоставления на сервере, либо для конечной точки. что позволит загружать и анализировать файл с сопоставлением непосредственно с вашим приложением.

Я бы посоветовал вам использовать RepositoryRestResource из Spring Data.

Прежде всего, создайте свою сущность:

public class Employee {
    //props
}

После этого создайте Employee Repository:

@RepositoryRestResource(collectionResourceRel = "employee", path = "employee")
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long> {

    List<Employee> findByLastName(@Param("firstName") String firstName);

}

И все, вы получите:

  • доступный для обнаружения REST API для вашей модели домена с использованием HAL в качестве типа носителя.
  • ресурсы коллекций, предметов и ассоциаций, представляющие ваш режим.
  • пагинация и сортировка

и так далее.

Ознакомьтесь с документами:

Весеннее руководство

Spring, округ Колумбия

Весенний проект отдыха данных

Другие вопросы по теме