0

I have Spring MVC web app running on Tomcat.

I upload a file and save it in the /tmp folder on the file system.

Then I need to show a link to that file in the view (Thymeleaf), so that the user can download the file by clicking on the link. How to do that?

I've heard about configuring Tomcat to allow a specific context to link to a folder on the FS, but not sure how to do that or if that is the only solution. Please help.

ACV
  • 9,964
  • 5
  • 76
  • 81

2 Answers2

1

The way I approach this is slightly different. Basically I use two controller actions for handling file uploads, one for uploading, and for downloading (viewing) files.

So upload action would save files to some preconfigured directory on the file system, I assume you already have that part working.

Then declare download action similar to this

@Controller
public class FileController {
     @RequestMapping("/get-file/{filename}")
     public void getFileAction(@RequestParam filename, HttpServletResponse response) {
         // Here check if file with given name exists in preconfigured upload folder
         // If it does, write it to response's output stream and set correct response headers
         // If it doesn't return 404 status code
     }
 }

If you want to make impossible to download file just by knowing the name, after uploading file, save some meta info to the database (or any other storage) and assign some hash (random id) to it. Then, in getFileAction, use this hash to look for file, not the original filename.

Finally, I would discourage using /tmp for file uploads. It depends on the system/application used, but generally temp directory are meant, as name suggest, for temporary data. Usually it is guaranteed data in the temp directory will stay for "reasonable time", but applications must take into account that content of temp directory can be deleted anytime.

Kejml
  • 2,114
  • 1
  • 21
  • 31
  • Thank you. so basically your approach is to have an action for downloading files. Nice approach, however I think this is an overhead. Why not just provide link to the file. However it seems that the context approach with Tomcat also uses a servlet - `DefaultServlet`. I am using `/tmp`, just for testing purposes. – ACV Sep 12 '15 at 17:10
  • 1
    I don't think the overhead of crating controller is huge unless zou are expecting traffic like Facebook has. I use this because I usually do more checks in the action. I guess you could use context aliases, if you are using tomcat 7, but I don't have direct experience with that: http://www.we3geeks.org/2012/03/04/tomcat-directory-aliases/ Note that the usage was changed in tomcat 8: http://stackoverflow.com/questions/25909329/after-migrating-to-tomcat-8-aliases-doesnt-work-any-more – Kejml Sep 12 '15 at 17:26
  • OK, this worked for me in Tomcat 8 `` – ACV Sep 12 '15 at 17:46
0

This is the precisely setup that worked for me (Tomcat 8, SpringMVC, boot):

  1. server.xml: <Context docBase="C:\tmp\" path="/images" />

  2. In the controller:

    public String createNewsSource(@ModelAttribute("newsSource") NewsSource source, BindingResult result, Model model,
            @RequestParam("attachment") final MultipartFile attachment) {
        new NewsSourceValidator().validate(source, result);
        if (result.hasErrors()) {
            return "source/addNewSource";
        }
        if (!attachment.isEmpty()) {
            try {
                byte[] bytes = attachment.getBytes();
                BufferedOutputStream stream = new BufferedOutputStream(
                        new FileOutputStream(new File("/tmp/" + attachment.getOriginalFilename())));
                stream.write(bytes);
                stream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        source.setLogo("images/" + attachment.getOriginalFilename());
        newsSourceService.createNewsSourceIfNotExist(source);
        return "redirect:/sources/list";
    }

As you can see I am saving the file to /tmp, but in the DB (source.setLogo()), I am pointing to images as mapped in server.xml

Here's where I found about Tomcat config:

If the images are all located outside the webapp and you want to have Tomcat's DefaultServlet to handle them, then all you basically need to do in Tomcat is to add the following Context element to /conf/server.xml inside tag:

This way they'll be accessible through http://example.com/images/....

SO answer to a similar question

Ali Behzadian Nejad
  • 8,804
  • 8
  • 56
  • 106
ACV
  • 9,964
  • 5
  • 76
  • 81