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