2

I have the following Spring boot method

@PostMapping("/download")
public String handleFileUpload(RedirectAttributes redirectAttributes) {
    Database db = new Database();

    try {
        List<String> usernames = db.getUsernames();
    } catch (Exception e) {
        e.printStackTrace();
    }

    return "download";

}

I want to the user to get a text file with the username on a line. Would I need to create the text file and save it to disk before sending it to the user? or can this be done without writing to disk?

Arya
  • 8,473
  • 27
  • 105
  • 175

2 Answers2

3

First, convert your List<String> to the text you want client to receive:

StringBuilder buf = new StringBuilder();
for (String username : usernames)
    buf.append(username).append("\r\n"); // or just "\n", your choice
String text = buf.toString();

Next, simply tell Spring that return value from method is the response itself, not a view name, by annotating method with @ResponseBody.

A String is automatically sent as text/plain.

@PostMapping("/download")
@ResponseBody
public String handleFileUpload(RedirectAttributes redirectAttributes) throws Exception {
    Database db = new Database();
    List<String> usernames = db.getUsernames();
    StringBuilder buf = new StringBuilder();
    for (String username : usernames)
        buf.append(username).append("\r\n"); // or just "\n", your choice
    return buf.toString();
}

UPDATE

To cause the returned text to pop-up the file download dialog, you need to set the Content-Disposition header.

To do that, you need to change return type to ResponseEntity<String> and then set the header values like this:

@GetMapping("/download")
public ResponseEntity<String> handleDownload() throws Exception {
    Database db = new Database();
    List<String> usernames = db.getUsernames();
    StringBuilder buf = new StringBuilder();
    for (String username : usernames)
        buf.append(username).append("\r\n"); // or just "\n", your choice
    return ResponseEntity.ok()
            .header("Content-Disposition", "attachment; filename=\"usernames.txt\"")
            .contentType(MediaType.TEXT_PLAIN)
            .body(buf.toString());
}
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • I change it to `@GetMapping("/download")` the page loads but it just hows it on the page. It never creates a file download. – Arya Apr 11 '18 at 04:25
0

No actually for file download you need and input stream which not necessary come from a file. Also not sure why you are using Post http verb for obtain (or get) a resource so I will suggest to use Get.

@GetMapping("/download")
public void getFile(HttpServletResponse response) {
    InputStream is = new ByteArrayInputStream(usernames.toString().getBytes(StandardCharsets.UTF_8));
    org.apache.commons.io.IOUtils.copy(is, response.getOutputStream());
    response.flushBuffer();
}

There are other spring facilities as @ResponseEntity that you may try to use for same purpose (file download).

@GetMapping("/download")
public ResponseEntity<Resource> download() throws IOException {
    InputStream resource = new ByteArrayInputStream(usernames.toString().getBytes(StandardCharsets.UTF_8));
    return ResponseEntity.ok().body(resource);
}
Juan Rada
  • 3,513
  • 1
  • 26
  • 26