javasqljsonspringmybatis

how to return Map<String, List<Object>> using mybatis


this is gpt writed code,but this can't return what I want, I want this function return a type of Map<String,List> data ,string is the categoryname

<resultMap id="articles" type="com.toc.content.pojo.Article">
        <result column="title" property="title" />
        <result column="content" property="content" />
        <result column="state" property="state"/>
    </resultMap>

    <resultMap id="CategoryArticleMap" type="java.util.HashMap">
        <id column="category_name" property="key"/>
        <collection property="value" ofType="com.toc.content.pojo.Article" resultMap="articles"/>
    </resultMap>

    <select id="getCategoryArticlesMap" resultMap="CategoryArticleMap">
        select c.category_name, a.title, a.content, a.state
        from category c
        left join article a
        on c.id = a.category_id
        where c.category_name is not null
        order by c.category_name
    </select>

in my ArticleDao.java

@MapKey("category_name")
Map<String, List<Article>> getCategoryArticlesMap();

I wanna get this type from json

{  "art":[
           {"title":"xxx",
            "author":"yyy"
           },
          {"title":"ppp",
            "author":"ssy"
           }, 
        ],
}


Solution

  • MyBatis cannot map results to such a complex java.util.Map directly, unfortunately.

    If the result has to be a Map, you can tell MyBatis to return a List of Maps and transform it in Java code.

    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;
    
    import org.apache.ibatis.annotations.Select;
    
    public interface Mapper {
      @Select("""
          select c.category_name, a.title, a.author
          from category c
          left join article a on c.id = a.category_id
          where c.category_name is not null
          order by c.category_name
          """)
      List<Map<String, Object>> selectMaps();
    
      default Map<String, List<Article>> getCategoryArticlesMap() {
        return selectMaps().stream().collect(Collectors.groupingBy(m -> (String) m.get("category_name"),
            Collectors.mapping(m -> new Article((String) m.get("title"), (String) m.get("author")), Collectors.toList())));
      }
    }
    

    Note that some DBs return column name in capitals.


    FYI, if you define a POJO, MyBatis can map the results directly.

    import java.util.List;
    
    public class CategoryWithArticles {
      private String categoryName;
      private List<Article> articles;
    
      public String getCategoryName() {
        return categoryName;
      }
    
      public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
      }
    
      public List<Article> getArticles() {
        return articles;
      }
    
      public void setArticles(List<Article> articles) {
        this.articles = articles;
      }
    }
    

    The mapper would look something like this.

    <resultMap type="test.Article" id="articleRM">
      <id property="title" column="title" />
      <result property="author" column="author" />
    </resultMap>
    
    <resultMap type="test.CategoryWithArticles" id="beanRM">
      <id property="categoryName" column="category_name"/>
      <collection property="articles" resultMap="articleRM" />
    </resultMap>
    
    <select id="selectBeans" resultMap="beanRM">
      select c.category_name, a.title, a.author
      from category c
      left join article a on c.id = a.category_id
      where c.category_name is not null
      order by c.category_name
    </select>
    

    Here is the mapper method signature.

    List<CategoryWithArticles> selectBeans();