Good afternoon, I would like to know if there is a way to send java file to html via javalin. In the documentation there is only about uploading html passing to java.
Explaining better, will be generated documents (pdf, xls and csv) in java, and I would like that by clicking a button (in html) the user download the generated file. Would it be possible ?
Before giving answer on pdf/xls/csv let's see how javalin handles application/json and text/html files (they're not so different from your documents).
/** Sets context result to specified html string and sets content-type to text/html. */
fun html(html: String): Context = contentType("text/html").result(html)
/**
* Serializes object to a JSON-string using JavalinJson and sets it as the context result.
* Sets content type to application/json.
*
* JavalinJson can be configured to use any mapping library.
*/
fun json(obj: Any): Context {
return contentType("application/json").result(JavalinJson.toJson(obj))
}
As we can see, javalin sets contentType (so browser knows how to interpret them) and then calls .result which accepts String or InputStream of your files.
Given the fact that you generate your files dynamically (and they aren't stored disk or in external server), we could do this:
package com.ernestas2k.hw;
import io.javalin.Javalin;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.net.URL;
import static io.javalin.apibuilder.ApiBuilder.get;
public class FileApp {
private static final String exampleCsv = "id,title,description\n" +
"1000,First product,First description\n" +
"1001,Second product,Second description";
public static void main(String[] args) {
Javalin app = Javalin.create();
app.routes(() -> {
get("/files/test-input-stream", ctx -> {
ctx.result(new ByteArrayInputStream(exampleCsv.getBytes()));
});
get("/files/test-string", ctx -> {
ctx.result(exampleCsv);
});
get("/files/test-pdf", ctx -> {
String pdfLink = "https://file-examples.com/wp-content/uploads/2017/10/file-sample_150kB.pdf";
BufferedInputStream pdfInputStream = new BufferedInputStream(new URL(pdfLink).openStream());
ctx.result(pdfInputStream).contentType("application/pdf");
});
get("/files/test-force-download", ctx -> {
ctx.result(exampleCsv)
.contentType("text/csv")
.header("Content-Disposition", "attachment; filename=example.csv");
});
});
app.start(7000);
}
}
try these examples in your browser. You'll notice first two come as text/plain (because we didn't specify what kind of file it is and browsers try to open it as text). The last example localhost:7000/files/test-pdf will be handled (previewed) as pdf file by browser.
Your job is to always specify so called mime type: text/csv, application/pdf, application/vnd.ms-excel or other). Since you know what kind of file you generate - you can set it as in the example above.
PS: I added 4th example of forcing file download (so browser don't preview it) from server side if you would like such thing.
Thank you so much!
You're welcome!
Hi everyone. The ernertas2k response did help, but it worked for me this way:
Changed the line
.header("Content-Disposition: attachment; filename=example.csv");
To
.header("Content-Disposition", "attachment; filename=example.csv");
The former way did not set neither the filename and csv format.
Good catch, for some reason thought .header(string) is "set full header name with value" but it's actually simple getter by header name. I've updated the code snippet.
Most helpful comment
Hi everyone. The ernertas2k response did help, but it worked for me this way:
Changed the line
.header("Content-Disposition: attachment; filename=example.csv");
To
.header("Content-Disposition", "attachment; filename=example.csv");
The former way did not set neither the filename and csv format.