1
votes

Point de terminaison Java REST pour renvoyer toutes les colonnes de base de données

Disons que j'ai une table postgres nommée Employee avec les colonnes suivantes:

  • ID
  • Prénom
  • Nom
  • Emploi
  • Date
  • Gestionnaire
  • Département

Je suis intéressé par un point de terminaison REST tel que / employee / {ID} renvoie toutes les informations pour cet employé en particulier au format JSON, mais si je spécifie / employee / {ID } / FirstName puis il renverrait le prénom de l'employé particulier uniquement au format JSON, / employee / {ID} / LastName renverrait le nom de famille de l'employé au format JSON, et ainsi de suite. Existe-t-il un bon moyen d'implémenter cela au lieu d'implémenter un point de terminaison pour accéder à chaque colonne? Merci.


4 commentaires

Ne pourriez-vous pas le faire avec un seul point final, c'est-à-dire. / employee / {id} / {attribute} et mapper attribute à un nom de colonne?


Je pense que c'est la solution que je recherche. Mais cela signifie-t-il également que dans ma fonction de point de terminaison, je devrais avoir une fonction de mappage qui va de l'attribut pour récupérer les colonnes? Je suppose que ma principale question est, pour le moment, il y a 7 colonnes dans la base de données et je peux la définir comme vous l'avez mentionné, mais s'il y a une 8e colonne qui est ajoutée à l'avenir, est-il possible que nous puissions créer le point de terminaison maintenant pour ne pas avoir à modifier le code lorsque la nouvelle colonne est ajoutée?


Lorsque j'utilise {attribute} dans le point de terminaison, c'est un joker - généralement implémenté à l'aide d'une PathVariable (ou équivalent). Assurez-vous que la bibliothèque que vous utilisez pour REST / MVC prend en charge cela. Si c'est le cas, vous devrez rédiger votre mappage. Le mappage devra changer si vous ajoutez une nouvelle colonne, mais pas votre point de terminaison.


Merci Je crois que le "mappage devra changer si vous ajoutez une nouvelle colonne" était ce que je voulais vraiment vérifier.


3 Réponses :


0
votes

Un moyen simple de résoudre ce problème consiste à utiliser un paramètre de requête au lieu de rechercher l'URL. En utilisant un paramètre comme fields , vous auriez une URL comme / employee / {id}? Fields = FirstName, LastName . En utilisant le code ci-dessous, vous pourriez avoir une Map qui serait sérialisée en JSON avec vos données. Comme ceci:

@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;
    }

}

Ce n'est cependant pas une bonne solution. Mais cela devrait fonctionner.


4 commentaires

C'est une solution risquée - vous feriez mieux de ne pas exposer les noms de colonnes sur votre API.


Eh bien, utilisez-le pour mapper votre DTO dans le contrôleur au lieu de mapper l'entité dans le service. C'est la même logique.


De cette façon, vous pouvez définir un contrôleur abstrait et centraliser la logique de mappage des champs de tous les DTO. Voyez-vous mon point?


Je vois ce que tu veux dire. Cependant, les colonnes (ou champs) de la base de données appartiennent à la couche d'accès aux données et ne doivent pas apparaître dans les contrôleurs. Tout mappage entre les attributs d'entité (faisant partie du modèle) et les concepts de base de données appartient à la couche d'accès aux données.



0
votes

Ainsi, comme @dave mentionné dans un commentaire, vous pouvez avoir un point de terminaison REST / employee / {ID} / {column} et dans votre contrôleur, vous aurez un mappage entre la valeur de { l'argument column} et le nom réel de la colonne dans la base de données. Si vous ne souhaitez pas redéployer votre application lors du mappage des modifications, vous pouvez la placer dans un fichier de propriétés distinct sur un serveur en dehors de votre jar / war et vous pouvez également ajouter un point de terminaison supplémentaire pour recharger le fichier de formulaire de mappage sur un serveur ou un point de terminaison cela permettra de télécharger et d'analyser un fichier avec mappage directement dans votre application.


0 commentaires

0
votes

Je vous suggère d'utiliser RepositoryRestResource à partir de Spring Data .

Tout d'abord, créez votre entité:

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

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

}
  • API REST détectable pour votre modèle de domaine en utilisant HAL comme type de média.
  • ressources de collection, d'élément et d'association représentant votre mode.
  • pagination et tri

et ainsi de suite.

Consultez la documentation:

Guide du printemps

Spring Dc

Projet Spring Data Rest


0 commentaires