Question

I am using the following data structure to store JDBC results in a Servlet controller prior to displaying in a JSP view using JSTL.

TreeMap
  - TreeMap
      - String[]

Four columns of data are returned per row.

"CATEGORY","OSDIRECTORY","FILENAME","DESCRIPTION"
"CATEGORY","OSDIRECTORY","FILENAME","DESCRIPTION"
"CATEGORY","OSDIRECTORY","FILENAME","DESCRIPTION"
etc.

The goal is to store the results in the data structure as

Category
    - FILENAME
        - OSDIRECTORY
        - DESCRIPTION

And to display the final results in the View as

Category A
    Hyperlink
    Hyperlink
    Hyperlink
Category B
    Hyperlink
    Hyperlink
etc.

Relevant Servlet Controller Code Snippet

...
TreeMap treeMap = new TreeMap();

rs = stmt.executeQuery(query); 

// Gather raw data
while(rs.next()){

    if(!treeMap.containsKey(rs.getString("CATEGORY"))){
        treeMap.put(rs.getString("CATEGORY"), new TreeMap());
    }

    String[] tmp = { rs.getString("OSDIRECTORY"), rs.getString("DESCRIPTION") };
    ((TreeMap)treeMap.get(rs.getString("CATEGORY"))).put(rs.getString("FILENAME"), tmp);
}

request.setAttribute("filemap", treeMap);

RequestDispatcher rd = request.getRequestDispatcher(VIEW_URL);

rd.forward(request, response);
...

Relevant JSP View JSTL Snippet

<c:forEach var="f" items="${filemap}">
    <h1><c:out value="${f.key}"/></h1>
    <c:forEach var="g" items="${filemap[f.key]}">
      <a href="TBD">
        <c:out value="${filemap[f.key][g.key][0]}"/>
        <c:out value="${filemap[f.key][g.key][1]}"/>
      </a>
    </c:forEach>
</c:forEach>

I am wondering of there is a more concise way to express some of the JSTL expressions.

For example ${filemap[f.key][g.key][0]} just seems too verbose to me.

Was it helpful?

Solution 2

After some later investigation and experimentation, I found this to be a cleaner approach than the JSTL posted in the question.

<c:forEach var="f" items="${filemap}">
    <h1><c:out value="${f.key}"/></h1>
    <c:forEach var="g" items="${f.value}">
        <a href="TBD">
            <c:out value="${g.value[0]}"/>
            <c:out value="${g.value[1]}"/>
        </a>
    </c:forEach>
</c:forEach>

OTHER TIPS

I would make objects to represent your data instead of using a map of maps. Since you have categories that contain files, make a category and file objects that look something like this:

public class Category {
    private String name;
    private List<DbFile> files = new ArrayList<DbFile>();
    // getters & setters for each property go here
}

public class DbFile {
    private String filename;
    private String osDirectory;
    private String description;
    // getters & setters for each property go here
}

Then in your data access code you can iterate over the result set and build up a list of categories objects like this:

Map<String, Category> categoryMap = new TreeMap<String, Category>();

while(rs.next()){
    String categoryName = rs.getString("CATEGORY");
    Category category = categoryMap.get(categoryName);

    if(!categoryMap.containsKey(categoryName)){
        category = new Category();
        category.setName(categoryName);
    }

    DbFile file = new DbFile();
    file.setFilename(rs.getString("FILENAME"));
    file.setOsDirectory(rs.getString("OSDIRECTORY"));
    file.setDescription(rs.getString("FILENAME"));

    category.getFiles().add(file);
    categoryMap.put(categoryName, category);
}

request.setAttribute("categories", Arrays.asList(categoryMap.values()));

Then the code on your page is much more straightforward:

<c:forEach var="category" items="${categories}">
   <h1><c:out value="${category.name}"/></h1>
   <c:forEach var="file" items="${category.files}">
       <a href="TBD">
           <c:out value="${file.osDirectory}"/>
           <c:out value="${file.description}"/>
       </a>
    </c:forEach>
</c:forEach>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top