web-dev-qa-db-fra.com

Retournez HashMap dans mybatis et utilisez-le comme ModelAttribute au printemps MVC

Je veux afficher la liste des catégories sur ma page Jsp en utilisant spring mvc @modelAttribute.

Dans mon fichier mapper.xml est

<select id="selectAllCategories" resultMap="BaseResultMap">
  select id, name from categories  
</select>

Dans ma classe Mapper.Java, j'ai une méthode

List<Map<String, String>> selectAllCategories();

Je veux avoir une méthode comme celle-ci:

Map<Integer, String>`selectAllCategories();

au lieu de List<Map<>>, est-ce possible?

21
user965884

Vous voulez obtenir un Map<Integer,String> Où l'entier est le id et la chaîne est le name. S'il y avait 200 catégories dans votre tableau, vous voudriez 200 entrées dans votre carte, plutôt qu'une liste de 200 cartes.

MyBatis ne peut pas tout à fait faire cela, mais vous pouvez utiliser ses installations pour le faire. Je vois deux options.

Option 1:

Le premier n'est pas tout à fait ce que vous avez demandé mais mérite d'être montré. Il vous donne un Map<Integer,Category> Où Category est un objet de domaine pour la table categories qui a id, nom (et éventuellement d'autres champs de la table categories). Une fois que vous avez créé l'objet de domaine Category, cela est assez facile à faire dans MyBatis en utilisant l'annotation @MapKey:

@Select("SELECT id, name FROM categories")
@MapKey("id")
Map<Integer,Category> getAllCategories();

Dans votre code, vous feriez alors:

MyMapper mapper = session.getMapper(MyMapper.class);
Map<Integer,Category> m = mapper.getAllCategories();

Cela peut ou non fonctionner pour votre cas d'utilisation selon que vous pouvez extraire le nom en tant que propriété de l'objet Category.


Option 2:

Pour obtenir le Map<Integer,String> Que vous avez demandé, la manière la plus simple que je connaisse est de créer une classe qui implémente l'interface MyBatis ResultHandler .

Votre ResultHandler utilisera la table de hachage par défaut de nom-colonne => valeur-colonne que MyBatis crée et crée une seule carte principale. Voici le code:

public class CategoryResultHandler implements ResultHandler {

  Map<Integer,String> inMap = new HashMap<Integer,String>(); 

  public Map<Integer, String> getIdNameMap() {
    return inMap;
  }

  @Override
  public void handleResult(ResultContext rc) {
    @SuppressWarnings("unchecked")
    Map<String,Object> m = (Map<String,Object>)rc.getResultObject();
    inMap.put((Integer)getFromMap(m, "id"), 
              (String)getFromMap(m, "name"));
  }

  // see note at bottom of answer as to why I include this method
  private Object getFromMap(Map<String, Object> map, String key) {
    if (map.containsKey(key.toLowerCase())) {
      return map.get(key.toLowerCase());
    } else {
      return map.get(key.toUpperCase());
    }
  }
}

La méthode handleResult est appelée une fois par ligne dans la table des catégories. Vous dites à MyBatis d'utiliser le ResultHandler puis d'extraire votre carte principale comme ceci:

CategoryResultHandler rh = new CategoryResultHandler();
session.select("getAllCategories", rh);
Map<Integer,String> m = rh.getIdNameMap();

L'un de ces deux devrait fonctionner pour vous.

Quelques notes finales:

  1. Pourquoi ai-je inclus la méthode d'assistance getFromMap()? Parce que vous ne pouvez pas toujours contrôler la casse du nom de colonne dans la table de hachage renvoyée par MyBatis. Plus de détails ici: mybatis- 3.1.1. Comment surcharger le resultmap retourné par mybatis

  2. J'ai des exemples de travail de ces solutions dans Koan26 des mybatis-koans (que j'ai ajouté en fonction de votre question): https://github.com/midpeter444/mybatis-koans

37
quux00