Reputation: 43
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?
Upvotes: 4
Views: 1714
Reputation: 209112
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();
}
};
Upvotes: 3