Upload and download image to project folder using Spring Boot

Asked

Viewed 3,383 times

0

I am developing a web module that I need to upload an image. Save to the project folder, I am using Apache’s Commons Io:

public class FileUtil {

    public static void saveFile(String path, MultipartFile file){

        File saveFile = new File(path);
        try {
        FileUtils.writeByteArrayToFile(saveFile, file.getBytes());
        } catch (IOException e) {
        e.printStackTrace();
        }
    }
}


@Autowired
private ServletContext servletContext;

@RequestMapping(value = "/salvar", method = RequestMethod.POST)
public String salvar(Event evento, Model model, @RequestParam("file") MultipartFile file) {
    if (file != null && !file.isEmpty()) {
        String path = servletContext.getRealPath("/") + "resources/imagens/" + evento.getName() + ".png";
        FileUtil.saveFile(path, file);
    }
    service.salvar(evento);
    return "redirect:/evento/formulario";
}

I am even able to save, but how to highlight this path in which the image was saved, in a link that can download the image and add as attribute of the Event class?

  • Do you want this link where, on a JSP page? What would this class be Event? The image can be accessed in a static way?

  • The link would be shown in a column of a table on an html page, show the link is no problem, the question would be how to recover this file that was uploaded and download it. The event class must have an image, but I am only keeping the image reference in a class attribute. Could be statically accessed yes.

1 answer

2


Create a method that receives the name of an image and download it, example:

@Controller
@EnableAutoConfiguration
public class Main {

    @Autowired
    private ServletContext servletContext;

    //Lista as imagens dentro da pasta resources/imagem numa JSP
    @RequestMapping("imagens")
    public ModelAndView imagens() throws IOException {

        ModelAndView mv = new ModelAndView("image-list");
        Set<String> nomeDasImagens = servletContext.getResourcePaths("/resources/imagens/").stream()
                                                    .map(FilenameUtils::getBaseName)
                                                    .collect(Collectors.toSet());
        mv.addObject("imagens", nomeDasImagens);
        return mv;
    }

    //Faz o download da imagem com o nome informado
    @RequestMapping(value = "download/{nome}", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<InputStreamResource> downloadImage(@PathVariable String nome) {
        InputStream is = servletContext.getResourceAsStream("/resources/imagens/" + nome + ".png");
        if(is == null) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
        }

        //Faça o que quiser aqui
        //Como criar um Event e atribuir o nome ou o caminho da imagem a ele

        return ResponseEntity.ok()
                .contentType(MediaType.IMAGE_PNG)
                .header("Content-disposition", "attachment; filename=" + nome + ".png")
                .body(new InputStreamResource(is));
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Main.class, args);
    }
}

JSP page listing all images:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Imagens</title>
    </head>
    <body>
        <c:forEach var="imagem" items="${imagens}">
            <a href="download/${imagem}">${imagem}</a><br />
        </c:forEach>
    </body>
</html>

Edit:

To just display the image, you can remove the header from ResponseEntity being like this:

return ResponseEntity.ok()
                .contentType(MediaType.IMAGE_PNG)
                .body(new InputStreamResource(is));

Another option is to access it statically:

For this add the following method:

@RequestMapping("imagens-estaticas")
public ModelAndView imagensEstaticas() throws IOException {

    ModelAndView mv = new ModelAndView("image-list");
    Map<String, String> nomeDasImagens = servletContext.getResourcePaths("/resources/imagens/").stream()
                                                .collect(Collectors.toMap(FilenameUtils::getBaseName, String::toString));
    mv.addObject("imagens", nomeDasImagens);
    return mv;
}

And change the JSP to:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Imagens</title>
    </head>
    <body>
        <c:forEach var="imagem" items="${imagens}">
            <a href="${imagem.value}">${imagem.key}</a><br />
        </c:forEach>
    </body>
</html>

Edit 2:

So you can download images in any format:

@RequestMapping("imagens")
public ModelAndView imagens() throws IOException {

    ModelAndView mv = new ModelAndView("image-list");
    Set<String> nomeDasImagens = servletContext.getResourcePaths("/resources/imagens/").stream()
                                                .map(FilenameUtils::getName)
                                                .collect(Collectors.toSet());
    mv.addObject("imagens", nomeDasImagens);
    return mv;
}

@RequestMapping(value = "download/{nome:.+}", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<InputStreamResource> downloadImage(@PathVariable String nome) throws FileNotFoundException {
    InputStream is = servletContext.getResourceAsStream("/resources/imagens/" + nome);
    if(is == null) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
    }
    return ResponseEntity.ok()
            .contentType(MediaType.parseMediaType("image/" + FilenameUtils.getExtension(nome)))
            .header("Content-disposition", "attachment; filename=" + nome)
            .body(new InputStreamResource(is));
}
  • It does not download in the requisica. It would have a way to only display the image on the page from the url?

  • @Marcelohenrique Strange, in my tests, when I click on the links of the images, the download is performed. I edited the answer to just show the image and not download it.

  • I made another code and managed to perform the download. I will now test this of just view..

  • Your code is correct, I did something wrong. Thank you! In this case, the only format that I could save in the folder would be PNG, by Mediatype tab? Or just switch to the ALL option would already solve?

  • @Marcelohenrique In the example I gave, I only put it in PNG format because it was the format you are saving according to the code in your question. It wouldn’t be necessary to switch to MediaType.ALL, but you would have to pass file extension next to the name and set the MediaType according to the file format. I edited my question and put an example.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.