Vuetify + Spring: How do I upload and display images correctly?

586 views Asked by At

I've done uploading and displaying images with Vuetify and Spring. It's work, but I'm not sure that I did it correctly. I am not sure that I have implemented the correct approach to solving this problem. Can you check it and say what you think?

On side Vuetify I use v-file-input component and axios for sending image to the server:

        <v-file-input
          v-model="selectedLogo"
          accept="image/png, image/jpeg, image/bmp"
          placeholder="Выберите Логотип"
          prepend-icon="mdi-camera"
          label="Логотип"
          show-size
        >
          <template v-slot:append-outer>
            <v-btn small @click="uploadLogo">
              <v-icon dense>mdi-upload</v-icon>
            </v-btn>
          </template>
        </v-file-input>


//...

uploadLogo(){
        uploadLogo(this.$axios, this.company.id, this.selectedLogo)
      }


//...

export const uploadLogo = function ($axios, id, logo) {
  let formData = new FormData()
  formData.append("logo", logo)
  return $axios.post(url+ `/${id}/logo`,
    formData,
    {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    })
}

In Spring I have RestController:

@RestController
@RequestMapping("/api/")
public class FileController {

    @Autowired
    private FileStorageService fileStorageService;

    @PostMapping("companies/{id}/logo")
    public ResponseEntity<Object> uploadFile(@PathVariable Long id, @RequestParam("logo") MultipartFile logo) {

        String fileName = fileStorageService.uploadLogo(id, logo);

        return new ResponseEntity<>(HttpStatus.OK);
    }

    @GetMapping("/companies/{id}/logo")
    public ResponseEntity<Resource> downloadLogo(@PathVariable Long id, HttpServletRequest request) {

        Resource resource = fileStorageService.loadLogoAsResource(id);

        String contentType = null;
        try {
            contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
        } catch (IOException ex) {
            contentType = "application/octet-stream";
        }

        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType(contentType))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
    }
}

fileStorageService:

@Service
public class FileStorageService {

    private final Path logoStorageLocation;

    @Autowired
    public FileStorageService(FileStorageProperties fileStorageProperties) {
        this.logoStorageLocation = Paths.get(fileStorageProperties.getLogoDir())
                .toAbsolutePath().normalize();

        try {
            Files.createDirectories(this.logoStorageLocation);
        } catch (Exception ex) {
            throw new FileStorageException("Could not create the directory where the uploaded files will be stored.", ex);
        }
    }

    public String uploadLogo(Long id, MultipartFile file) {

        String fileExtension = StringUtils.getFilenameExtension(file.getOriginalFilename());

        String fileName = id.toString() + "." + fileExtension;

        try {
            if(fileName.contains("..")) {
                throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName);
            }
            Path targetLocation = this.logoStorageLocation.resolve(fileName);
            Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);

            return fileName;
        } catch (IOException ex) {
            throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex);
        }
    }

    public Resource loadLogoAsResource(Long id) {

        String fileName = id.toString() + ".png";
        try {
            Path filePath = this.logoStorageLocation.resolve(fileName).normalize();
            Resource resource = new UrlResource(filePath.toUri());
            if(resource.exists()) {
                return resource;
            } else {
                throw new FileNotFoundException("File not found " + fileName);
            }
        } catch (MalformedURLException ex) {
            throw new FileNotFoundException("File not found " + fileName, ex);
        }
    }

}

My idea is uploading/displaying images by URL http://server/api/companies/{id}/logo without knowing the name of the logo file.

For displaying I use v-img component:

 <v-img :src="'http://localhost:8081/api/companies/' + company.id +'/logo'"></v-img>

Questions:

  1. What do you think about my solution?

  2. Here I use RestController for displaying images. I thought that I can get image directly by its location on the server. Without using RestController for @GetMapping. For example, if my images are stored in the folder with path /images/companies/logo on the server, I can get my images by URL with path http://server/images/companies/logo/namelogo.png

In this way, I should know name of the file on the server.

How can I display the image without using RestController for @GetMapping?

0

There are 0 answers