How to Implement SpringBoot-based Image Upload and Download?

It’s a common requirement in developing Java web to implement a file or image upload and download function. In this post, I’d like to show how to implement the SpringBoot-based image upload and download function.

How to Implement SpringBoot-based Image Upload and Download?

Usually, if projects with a lot of images, the images will be placed on a dedicated server and not directly on the server where the business code is located. The following example is just to learn the basic process, so it saves the uploaded image to the Database.

How to implement upload images on the projects based on Spring?

The following is just the core code of the implementation of uploading images on the projects based on Spring Boot.

Image upload HTML code:

<form action="http:\\localhost" method="post" enctype="multipart/form-data"
                  th:action="@{'/upload/image'}">
                <label class="control-label">Select File</label>
                <input id="imagefile" name="imagefile" type="file" class="file">
                <button type="submit" class="btn btn-primary">Submit</button>
   </form>

It’s an HTML page based on thymeleaf.

ImageController

// to get image upload page
@GetMapping
@RequestMapping("/recipe/{id}/image")
public String getImageUploadForm(@PathVariable String id, Model model) {

        model.addAttribute("recipe", recipeService.findCommandById(Long.valueOf(id)));

        return "recipe/imageuploadform";
    }

// handle the uploaded image, save it to database
@PostMapping("/recipe/{id}/image")
public String handleImagePost(@PathVariable String id, @RequestParam("imagefile") MultipartFile multipartFile) throws IOException {

        imageService.saveImageFile(Long.valueOf(id), multipartFile);

        return "redirect:/recipe/{id}/show";
    }

// read image from databae and render it to front page.
@GetMapping("/recipe/{id}/recipeimage")
 public void renderImageFromDB(@PathVariable String id, HttpServletResponse response) throws IOException {
        RecipeCommand recipeCommand = recipeService.findCommandById(Long.valueOf(id));

        if (recipeCommand.getImage() != null) {
            byte[] byteArray = new byte[recipeCommand.getImage().length];

            int i = 0;
            for (Byte b: recipeCommand.getImage()) {
                //auto unboxing
                byteArray[i++] = b;
            }

            response.setContentType("image/jpeg");
            InputStream is = new ByteArrayInputStream(byteArray);

            IOUtils.copy(is, response.getOutputStream());
        }
    }

GetMapping annotation already wraps @RequestMapping(method = RequestMethod.GET) by default

So, it is more convenient than using @RequestMapping(path = "/{city_id}/{user_id}",method = RequestMethod.GET).

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(
    method = {RequestMethod.GET}
)
public @interface GetMapping {
    ...
}

ImageService

@Service
public class ImageServiceImpl implements ImageService {

    private final RecipeRepository recipeRepository;

    public ImageServiceImpl(RecipeRepository recipeRepository) {
        this.recipeRepository = recipeRepository;
    }

    // save image(MultipartFile) to database
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveImageFile(Long recipeId, MultipartFile file) {

        try {
            Recipe recipe = recipeRepository.findById(recipeId).get();

            Byte[] byteObjects = new Byte[file.getBytes().length];

            int i = 0;
            for (byte b : file.getBytes()) {
                byteObjects[i++] = b;
            }

            recipe.setImage(byteObjects);
            recipeRepository.save(recipe);
        } catch (IOException e) {
            log.error("Error occurred", e);

            e.printStackTrace();
        }
    }
}

How to show the image read from the database?

We just need to set the request of the image to match with the @GetMapping("/recipe/{id}/recipeimage") in ImageController.

So, the request for the image in the HTML page can be like this:

 <img th:src="@{'/recipe/' + ${recipe.getId()} + '/recipeimage'}" />

How to implement the file download function in Java Web development?

Usually, there are two ways to implement the download function in a Java web project.

Method 1:

The web front end does not do any processing and directly access the address of the background, such as http://localhost:8080/download/file.

The application back-end returns the output stream of the file, the browser will automatically be converted it into a file and start downloading.

Method 2:

The back-end does not do the processing, only provides a data interface, the front-end receives the data, via JavaScript will be organized and converted into the corresponding format of the file, such as doc, pdf, and so on.

Recommend

I’d like to recommend the use of the first method. Because when the amount of data is relatively large, through the front-end export words, the background needs to pass a large amount of data to the front-end, then the pressure is relatively large.

If file uploads and downloads are frequently used, such as electronic filing systems, e-books, web drives, etc. Then you need to consider using a dedicated file server to split the business and ease the pressure on the server side.