Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I think my scenario is pretty common. I have a database and I want my Spring MVC app to accept a request in the controller, invoke the DB service to get data and send that data to the client as a CSV file. I'm using the JavaCSV library found here to assist in the process: http://sourceforge.net/projects/javacsv/

I've found several examples of people doing similar things and cobbled together something that looks correct-ish. When I hit the method, though, nothing is really happening.

I thought writing the data to the HttpServletResponse's outputStream would be sufficient, but apparently, I'm missing something.

Here's my controller code:

@RequestMapping(value="/getFullData.html", method = RequestMethod.GET)
public void getFullData(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws IOException{
    List<CompositeRequirement> allRecords = compReqServ.getFullDataSet((String)session.getAttribute("currentProject"));

    response.setContentType("data:text/csv;charset=utf-8"); 
    response.setHeader("Content-Disposition","attachment; filename=yourData.csv"");
    OutputStream resOs= response.getOutputStream();  
    OutputStream buffOs= new BufferedOutputStream(resOs);   
    OutputStreamWriter outputwriter = new OutputStreamWriter(buffOs);  

    CsvWriter writer = new CsvWriter(outputwriter, 'u0009');  
    for(int i=1;i <allRecords.size();i++){              
        CompositeRequirement aReq=allRecords.get(i);  
        writer.write(aReq.toString());  
    }     
    outputwriter.flush();   
    outputwriter.close();

};

What step am I missing here? Basically, the net effect is... nothing. I would have thought setting the header and content type would cause my browser to pick up on the response and trigger a file download action.

See Question&Answers more detail:os

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

1 Answer

It seems to be because your Content-type is set incorrectly, it should be response.setContentType("text/csv;charset=utf-8") instead of response.setContentType("data:text/csv;charset=utf-8").

Additionally, if you are using Spring 3, you should probably use a @ResponseBody HttpMessageConverter for code reuse. For example:

  • In the controller:

    @RequestMapping(value = "/getFullData2.html", method = RequestMethod.GET, consumes = "text/csv")
    @ResponseBody // indicate to use a compatible HttpMessageConverter
    public CsvResponse getFullData(HttpSession session) throws IOException {
          List<CompositeRequirement> allRecords = compReqServ.getFullDataSet((String) session.getAttribute("currentProject"));
          return new CsvResponse(allRecords, "yourData.csv");
    }
    
  • plus a simple HttpMessageConverter:

    public class CsvMessageConverter extends AbstractHttpMessageConverter<CsvResponse> {
       public static final MediaType MEDIA_TYPE = new MediaType("text", "csv", Charset.forName("utf-8"));
       public CsvMessageConverter() {
           super(MEDIA_TYPE);
       }
    
       protected boolean supports(Class<?> clazz) {
           return CsvResponse.class.equals(clazz);
       }
    
       protected void writeInternal(CsvResponse response, HttpOutputMessage output) throws IOException, HttpMessageNotWritableException {
           output.getHeaders().setContentType(MEDIA_TYPE);
           output.getHeaders().set("Content-Disposition", "attachment; filename="" + response.getFilename() + """);
           OutputStream out = output.getBody();
           CsvWriter writer = new CsvWriter(new OutputStreamWriter(out), 'u0009');
           List<CompositeRequirement> allRecords = response.getRecords();
           for (int i = 1; i < allRecords.size(); i++) {
                CompositeRequirement aReq = allRecords.get(i);
                writer.write(aReq.toString());
           }
           writer.close();
       }
    }
    
  • and a simple object to bind everything together:

    public class CsvResponse {    
       private final String filename;
       private final List<CompositeRequirement> records;
    
       public CsvResponse(List<CompositeRequirement> records, String filename) {
           this.records = records;
           this.filename = filename;
       }
       public String getFilename() {
           return filename;
       }
       public List<CompositeRequirement> getRecords() {
           return records;
       }
    }
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...