Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Export CSV File - JAX RS - REST - AJAX

I create a function to download a CSV File. I will use that to download simple reports. I got the error below on Netbeans using Wildfly and JAX RS

RESTEASY002005: Failed executing POST /reports/downloadCSV/: org.jboss.resteasy.core.NoMessageBodyWriterFoundFailure: Could not find MessageBodyWriter for response object of type: java.io.FileWriter of media type: application/octet-stream

Here is my Code:

Controller

Update on ParametersClass

@POST
@Path("/downloadCSV")
@Produces("application/octet-stream")
public Response downloadCSV(ParametersClass param) {
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    FileWriter fileWriter = null;
    Date date = new Date();
    try {
        fileWriter = new FileWriter("MainReport_"+dateFormat.format(date)+".csv");
        fileWriter.append(csvService.mainReport(dateFormat.parse(param.getStartDate()),dateFormat.parse(param.getEndDate())));
        fileWriter.flush();
        fileWriter.close();

        ResponseBuilder response = Response.ok((Object) fileWriter);  
        response.header("Content-Disposition","attachment; filename=\"MainReport_"+dateFormat.format(date)+".csv\"");  
        return response.build();  
    } catch (ParseException ex) {
        ex.printStackTrace();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}

The csvService returns a String like:

 Column1,column2,column3
 cellInfo1,cellInfo2,cellInfo3
 ,cellInfo2,cellInfo3
 cellInfo1,,cellInfo3
 cellInfo1,cellInfo2,
 ,,cellInfo3

I tried using a different @Produces => @Produces('text/csv') , @Produces('application/octet-stream')

If I remove the Annotation @Produces I got the following error:

RESTEASY002010: Failed to execute: javax.ws.rs.NotSupportedException: RESTEASY003200: Could not find message body reader for type: class com.xo.CSVFile of content type: application/x-www-form-urlencoded;charset=UTF-8

AJAX

     var dateRange = new Object();
     dateRange.startDate = '2017-07-20';
     dateRange.endDate = '2017-08-10';
     $.ajax({
          type: 'POST',
          url: appPath + '/api/reports/downloadCSV/',
          data: JSON.stringify(dateRange),
          async:true,
          success: function(data) {
           }
     });

What I'm doing wrong ? Could you help to me please!

.

SOLUTION Thanks to @albert-bos

1st. Check the link in the solution from @albert-bos below.

2nd: Check this link too

3rd:

Controller:

@POST
@Path("/downloadCSV")
@Produces("text/csv")
public List<LinkedHashMap<String, String>> downloadCSV(ParametersClass param) {
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    try {
        return csvService.mainReport(dateFormat.parse(param.getStartDate()),dateFormat.parse(param.getEndDate()));
    } catch (ParseException ex) {
        return null;
    }
}

MessageBodyWriter: I create a class called CSVMessageBodyWritter (check the link) but I adpated the method writeTo:

 @Override
 public void writeTo(Object t, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
      CsvSchema schema = null;
      CsvSchema.Builder schemaBuilder = CsvSchema.builder();
      if(t!=null){
           List<LinkedHashMap<String, String>> reportArray = (List<LinkedHashMap<String, String>>) t;
           LinkedHashMap<String, String> headers = reportArray.get(0);

           for (String col : headers.keySet()) {
                 schemaBuilder.addColumn(col);
           }
           schema = schemaBuilder.build().withLineSeparator("\r");
           CsvMapper mapper = new CsvMapper();
           mapper.writer(schema).writeValues(entityStream).writeAll(reportArray);
      }
 }
like image 325
Chris Sum Avatar asked Oct 19 '25 18:10

Chris Sum


2 Answers

JAX-RS only supports a few Content-Types by default (also depending on implementation), like XML and JSON.

The idea of JAX-RS is that it will convert an object to a certain type (e.g. XML or JSON). This is so you can re-use the same object for XML and JSON, without knowing the output in your Controller. Then If you want something different like CSV, you need to define your own BodyWriter, see example here: http://www.javaprocess.com/2015/08/a-simple-csv-messagebodywriter-for-jax.html

The problem here is that your controller is to specific for CSV and isn't very flexible. You could put your output of csvService into an object and let the BodyWriter convert it into CSV.

like image 157
Albert Bos Avatar answered Oct 21 '25 09:10

Albert Bos


JS

window.open("http://localhost:8080/xmlcompare-rs/xmlcompare/excelmisreport");

Rest

@GET
@Path("excelmisreport")
@Produces("application/vnd.ms-excel")
public Response getExcelReport() {
    ResponseBuilder response = Response.ok((Object) file);
    response.header("Content-Disposition",
        "attachment; filename=MISReport.xls");
    return response.build();
}
like image 40
Raja Ramachandran Avatar answered Oct 21 '25 08:10

Raja Ramachandran