Showing posts with label Rendering CSV CSVVIEW ERT BHUB Spring. Show all posts
Showing posts with label Rendering CSV CSVVIEW ERT BHUB Spring. Show all posts

Thursday, December 16, 2010

Rendering CSV as ERT from BHUB with Spring

As I showed for Excel we can create a custom View to render tabular data in CSV format instead.

Note that this example uses Spring and a ControllerContext class that I use to pass information about different layers (Context-Object pattern). You can of course get the fundamental idea in case you do not use a ControllerContext in your design.

The unique dependency:
<dependency>
            <groupId>net.sf.opencsv</groupId>
            <artifactId>opencsv</artifactId>
            <version>2.0</version>
</dependency>

The Controller is very similar to the one I presented for the ExcelView post. Just a little modification so actually we can render either Excel or CSV:
package com.nestorurquiza.spring.web;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.nestorurquiza.spring.web.ExcelView;
import com.nestorurquiza.spring.web.CsvView;

@Controller
public class TabularController extends RootController {

    @RequestMapping("/board")
    public ModelAndView welcomeHandler(HttpServletRequest request,
            HttpServletResponse response) {
        //Initialize the context (mandatory)
        ControllerContext ctx = new ControllerContext(request, response);
        init(ctx);
        
        DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
        Map<String, List<Map<String, Object>>> excelWorkbookViewMap = new HashMap<String, List<Map<String, Object>>>();
        List<Map<String, Object>> excelRows = new ArrayList<Map<String, Object>>();
        try {
            Map<String, Object> excelRow = new HashMap<String, Object>(); 
            excelRow.put("Name", "Gregory");
            excelRow.put("Age", 33);
            excelRow.put("Salary", 33000.55);
            excelRow.put("DOB", df.parse("2/1/1980"));
            excelRow.put("Graduated", false);
            excelRow.put("Comments", "He is our \"report designer\"");
            excelRows.add(excelRow);
            excelRow = new HashMap<String, Object>(); 
            excelRow.put("Name", "Mark");
            excelRow.put("Age", 41);
            excelRow.put("Salary", 33000.55);
            excelRow.put("DOB", df.parse("20/12/1975"));
            excelRow.put("Graduated", true);
            excelRow.put("Comments", "He is our \"web designer\"");
            excelRows.add(excelRow);
            excelWorkbookViewMap.put("First Sheet", excelRows);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        String ert = ctx.getParameter("ert");
        String baseFilename = "board";
        if("csv".equals(ert)) {
            Map<String, List<Map<String, Object>>> csvViewMap = new HashMap<String, List<Map<String, Object>>>();
            String fileName = baseFilename + ".csv";
            csvViewMap.put(fileName, excelRows);
            return new ModelAndView(new CsvView(ctx, fileName, ','), csvViewMap);
        } else {
            String fileName = baseFilename + ".xls";
            return new ModelAndView(new ExcelView(ctx, fileName), excelWorkbookViewMap);
        }
    }
}
The CsvView:
package com.nestorurquiza.spring.web;

import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.view.AbstractView;

import au.com.bytecode.opencsv.CSVWriter;

import com.nestorurquiza.utils.Utils;
import com.nestorurquiza.web.ControllerContext;


public class CsvView extends AbstractView {
    private static final String CONTENT_TYPE = "text/csv";

    public CsvView(ControllerContext ctx, String fileName, char fieldSeparator) {
        super();
        if(Utils.isEmpty(fileName)) {
            fileName = "fileName";
        }
        this.fileName = fileName;
        this.fieldSeparator = fieldSeparator;
        this.ctx = ctx;
        setContentType(CONTENT_TYPE);
    }
    
    private String fileName;
    private char fieldSeparator;
    private ControllerContext ctx; 

    /**
     * 
     * model: Map<String, List<Map, Object>>
     * This view returns back a CSV stream
     * The model must come with an entry for fileName key
     * Each list entry (the list map) corresponds to a row
     * The headers for each row are the list map keys
     * The comma separated values are the list map values
     * 
     * @author nestor
     *
     */
    protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        CSVWriter writer = new CSVWriter(response.getWriter(), fieldSeparator);

        if (Utils.isEmpty(model)) {
            writer.writeNext("error.empty.model".split(""));
        } else {
            Set<Map.Entry<String, List<Map<String, Object>>>> set = model.entrySet();
            for (Map.Entry<String, List<Map<String, Object>>> entry : set) {
                String key = entry.getKey();
                if (fileName.equals(key)) {
                    List<Map<String, Object>> content = entry.getValue();
                    int rowCount = 0;
                    for (Map<String, Object> row : content) {
                        if (rowCount == 0) {
                            String[] tokens = new String[row.size()];
                            int i = 0;
                            for( String cellName : row.keySet() ) {
                                tokens[i] = cellName;
                                i++;
                            }
                            writer.writeNext(tokens);
                        }
                        String[] tokens = new String[row.size()];
                        int i = 0;
                        for( String cellName : row.keySet() ) {
                            Object cellValue = row.get(cellName);
                            tokens[i] = cellValue.toString();
                            i++;
                        }
                        writer.writeNext(tokens);
                        rowCount++;
                    }

                }
            }
        }
        writer.flush();
    }
}

Followers