Search code examples
spring-bootbase64

How to convert base64 to MultipartFile in Java


I have a problem. I want to convert BufferedImage to MultipartFile. First, on my UI I send a base64 String to the server, and on my server, I convert it to BufferedImage. After that, I want to convert BufferedImage to MultipartFile and save it on the local storage. This is my Controller method:

@PostMapping("/saveCategory")
@ResponseStatus(HttpStatus.OK)
public void createCategory(@RequestBody String category) {
                    
    BufferedImage image = null;
    OutputStream stream;
    byte[] imageByte;
    
    try {
        BASE64Decoder decoder = new BASE64Decoder();
        imageByte = decoder.decodeBuffer(category);
        ByteArrayInputStream bis = new ByteArrayInputStream(imageByte);
        image = ImageIO.read(bis);
        bis.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    String fileName = fileStorageService.storeFile(image);

My storage method:

public String storeFile(MultipartFile file) {
    // Normalize file name
    String fileName = StringUtils.cleanPath(file.getOriginalFilename());
    
    try {
        // Check if the file's name contains invalid characters
        if (fileName.contains("..")) {
            throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName);
        }
    
        // Copy file to the target location (Replacing existing file with the same name)
        Path targetLocation = this.fileStorageLocation.resolve(fileName);
        Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
    
        return fileName;
    } catch (IOException ex) {
        System.out.println(ex);
        throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex);
    }
}

Solution

  • Such conversion from base64 to MultipartFile is done by Spring automatically. You just need to use correct annotations.

    You can create a wrapper dto class holding all necessary data.

    public class FileUploadDto {
        private String category;
        private MultipartFile file;
        // [...] more fields, getters and setters
    }
    

    Then you can use this class in your controller:

    @RestController
    @RequestMapping("/upload")
    public class UploadController {
    
        private static final Logger logger = LoggerFactory.getLogger(UploadController.class);
    
        @PostMapping
        public void uploadFile(@ModelAttribute FileUploadDto fileUploadDto) {
            logger.info("File upladed, category= {}, fileSize = {} bytes", fileUploadDto.getCategory(), fileUploadDto.getFile().getSize());
        }
    
    }
    

    The reason I didn't get the point of the question on a first glance was @RequestBody String category. I think this is a very very misleading variable name for a file. However, I created the DTO class with the category field aswell so you could include it in your request.

    Of course, then you get rid of your controller logic and simply call the service method like fileStorageService.storeFile(fileUploadDto.getFile()); or pass the whole file and make use of category field.

    edit

    I also include the request sent from Postman and some console output:

    Postman request and console output