I am trying to generate a .csv file as response to a restful webservice(using Jersey). So far, I am able to get a List<HashMap<String, String>> and the key should be the CSV header and value should be the CSV data.
I am using the Jackson API for CSV generation.
The code flow is:
I get the data from DAO class in List<HashMap<String, String>> name of the list is myArrList.
My first doubt is is this a good idea to provide the file location like this in real scenario? How else can I do this? How can I send a file with data without actually creating a file in local system?
File file = new File( "C:/Users/.../Downloads/RadioObjectData.csv");
Writer writer = null;
ResponseBuilder response = null;
Reader reader = null;
//Copy List of Map Object into CSV format at specified File location.
try
{
     writer = new FileWriter( file, false);
     reader = new FileReader( file);
     csvWriter( myArrList, writer);
     // csvReader( reader);
     response = Response.ok( (Object)file);
     response.header( "Content-Disposition", "attachment; filename=\"RadioObjectData.csv\"");
     // return response.build();
}
catch (IOException e)
{
     // TODO Auto-generated catch block
     e.printStackTrace();
}
//Read CSV format from specified File location and print on console..
return response.build();
and now I send this List to the csvWriter method to create a .csv file in my system so that then I can send this same file as response to the webservice.(Is this approach ok?)
public static void csvWriter( List<HashMap<String, String>> listOfMap, Writer writer) throws IOException
{
  CsvSchema schema = null;
  CsvSchema.Builder schemaBuilder = CsvSchema.builder();
  if (listOfMap != null && !listOfMap.isEmpty())
  {
     for (String col: listOfMap.get( 0).keySet())
     {
        schemaBuilder.addColumn( col);
     }
     schema = schemaBuilder.build().withLineSeparator( "\r").withHeader();
  }
  CsvMapper mapper = new CsvMapper();
  mapper.writer( schema).writeValues( writer).writeAll( listOfMap);
  writer.flush();
}
Now a .csv file is getting created in my C drive at the given location.
I want this CSV to be encoded in base64 before sending it as a response.
How can I achieve all of this?
Just use a StreamingOutput as the Response entity.
interface StreamingOutput {
    void write(OutputStream out);
}
You just implement this interface and pass it to the Response.ok() method. What you would do in this case is just wrap the OutputStream in a OutputStreamWriter, so that you can pass it to the CsvMapper.writeValues(Writer) method.
StreamingOutput entity = new StreamingOutput() {
    @Override
    public void write(OutputStream out) {
        Writer writer = new BufferedWriter(
                new OutputStreamWriter(out, StandardCharsets.UTF_8));
        csvWriter(myArrList, writer);
        out.flush();
    }
};
return Response.ok(entity)
        .header(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=\"RadioObjectData.csv\"")
        .build();
That's all you need. No need to any intermediate storage.
If you want to Base64 encode the CSV file, what you can do is write to a ByteArrayOutputStream and use those byte to encode with the Base64 class. After it is encoded, just write the encoded bytes to the StreamingOutput OutputStream. Here is an example.
StreamingOutput entity = new StreamingOutput() {
    @Override
    public void write(OutputStream out) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedWriter baosWriter = new BufferedWriter(
                new OutputStreamWriter(baos, StandardCharsets.UTF_8));
        csvWriter(myArrList, baosWriter);
        byte[] bytes = baos.toByteArray();
        byte[] base64Encoded = Base64.getEncoder().encode(bytes);
        out.write(base64Encoded);
        out.flush();
    }
};
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With