Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
370 views
in Technique[技术] by (71.8m points)

java - Return HashMap in mybatis and use it as ModelAttribute in spring MVC

I want to display list of categories in my Jsp page using spring mvc @modelAttribute.

In my mapper.xml file is

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

In my Mapper.java class I have method

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

I want to have a method like this:

Map<Integer, String>`selectAllCategories();

instead of List<Map<>>, is that possible?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You want to get a Map<Integer,String> where the Integer is the id and the String is the name. If there were 200 categories in your table, you would want 200 entries in your map, rather than a list of 200 maps.

MyBatis can't quite do that out of the box, but you can use its facilities to do that. I see two options.

Option 1:

The first isn't quite what you asked for but is worth showing. It gives you a Map<Integer,Category> where Category is a domain object for the categories table that has id, name (and possibly other fields from the categories table). After you've created the Category domain object, this is quite easy to do in MyBatis using the @MapKey annotation:

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

In your code you would then do:

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

That may or may not work for your use case depending on whether whether you can extract the name as a property of the Category object.


Option 2:

To get the Map<Integer,String> you asked for, the easiest way I know is to create a class that implements the MyBatis ResultHandler interface.

Your ResultHandler will use the default hashmap of column-name => column-value that MyBatis creates and create a single master Map. Here's the 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());
    }
  }
}

The handleResult method gets called once per row in the category table. You tell MyBatis to use the ResultHandler and then extract your master map like this:

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

One of those two should work for you.

A few final notes:

  1. Why did I include the getFromMap() helper method? Because you can't always control the case of the column name in the hashmap that MyBatis returns. More details here: mybatis- 3.1.1. how to override the resultmap returned from mybatis

  2. I have working examples of these solutions in Koan26 of the mybatis-koans (which I added based on your question): https://github.com/midpeter444/mybatis-koans


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...