Implement Image Upload and Cropping with vue-cropper in Vue and Send to SpringBoot Backend

This article walks through integrating the vue-cropper plugin into a Vue project to enable avatar cropping with real‑time preview, handling image upload via ElementUI, and transmitting the cropped image to a SpringBoot backend using a FormData POST request.

The Dominant Programmer
The Dominant Programmer
The Dominant Programmer
Implement Image Upload and Cropping with vue-cropper in Vue and Send to SpringBoot Backend

Scenario

In a front‑end/back‑end separated project, the avatar must be cropped with a live preview before being uploaded to a SpringBoot backend.

Plugin repository

https://github.com/xyxiao001/vue-cropper

Installation

npm install vue-cropper

Importing the plugin

Component‑level import:

import { VueCropper } from 'vue-cropper'
export default {
  components: { VueCropper }
}

Global import (main.js):

import VueCropper from 'vue-cropper'
Vue.use(VueCropper)

CDN usage:

<script src="//cdn.jsdelivr.net/npm/[email protected]/dist/index.js"></script>
Vue.use(window['vue-cropper'].default)

Dialog layout

<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened">
  <el-row>
    <el-col :xs="24" :md="12" :style="{height: '350px'}">
      <vue-cropper
        ref="cropper"
        :img="options.img"
        :info="true"
        :autoCrop="options.autoCrop"
        :autoCropWidth="options.autoCropWidth"
        :autoCropHeight="options.autoCropHeight"
        :fixedBox="options.fixedBox"
        @realTime="realTime"
        v-if="visible"
      />
    </el-col>
    <el-col :xs="24" :md="12" :style="{height: '350px'}">
      <div class="avatar-upload-preview">
        <img :src="previews.url" :style="previews.img" />
      </div>
    </el-col>
  </el-row>
  <el-row>
    <el-col :lg="2" :md="2">
      <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
        <el-button size="small">Upload<i class="el-icon-upload el-icon--right"></i></el-button>
      </el-upload>
    </el-col>
    <el-col :lg="{span: 1, offset: 2}" :md="2">
      <el-button icon="el-icon-plus" size="small" @click="changeScale(1)"></el-button>
    </el-col>
    <el-col :lg="{span: 1, offset: 1}" :md="2">
      <el-button icon="el-icon-minus" size="small" @click="changeScale(-1)"></el-button>
    </el-col>
    <el-col :lg="{span: 1, offset: 1}" :md="2">
      <el-button icon="el-icon-refresh-left" size="small" @click="rotateLeft()"></el-button>
    </el-col>
    <el-col :lg="{span: 1, offset: 1}" :md="2">
      <el-button icon="el-icon-refresh-right" size="small" @click="rotateRight()"></el-button>
    </el-col>
    <el-col :lg="{span: 2, offset: 6}" :md="2">
      <el-button type="primary" size="small" @click="uploadImg()">Submit</el-button>
    </el-col>
  </el-row>
</el-dialog>

Component state

data() {
  return {
    open: false, // dialog visibility
    previews: {} // preview data from cropper
  }
}

Open dialog

editCropper() {
  this.open = true;
}

Options object

options: {
  img: 'https://images.cnblogs.com/.../qrcode_for_gh_f76a8d7271eb_258.jpg',
  autoCrop: true,
  autoCropWidth: 200,
  autoCropHeight: 200,
  fixedBox: true
}

Real‑time preview

The cropper emits @realTime="realTime". The handler stores the preview data:

realTime(data) {
  this.previews = data;
}

Cropper API used

rotateLeft()

– rotate the image 90° left. rotateRight() – rotate the image 90° right. changeScale(num) – zoom the image (positive to enlarge, negative to shrink). getCropBlob(callback) – obtain the cropped image as a Blob.

Upload handling

ElementUI el-upload is configured with a custom request to suppress automatic network upload.

// Override default upload behavior
requestUpload() {
  // custom logic can be placed here
}

// Pre‑upload validation and conversion to base64
beforeUpload(file) {
  if (file.type.indexOf('image/') === -1) {
    this.msgError('File format error, please upload an image (JPG, PNG, etc.).');
  } else {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => {
      this.options.img = reader.result;
    };
  }
}

Submit cropped image

uploadImg() {
  this.$refs.cropper.getCropBlob(data => {
    let formData = new FormData();
    formData.append('file', data);
    uploadimg(formData).then(response => {
      if (response.code === 200) {
        this.open = false;
        this.options.img = process.env.VUE_APP_BASE_API + response.data;
        this.$emit('changezp', this.options.img);
        this.msgSuccess('Modification successful');
      }
      this.visible = false;
    });
  });
}

The helper uploadimg sends the FormData to the backend.

SpringBoot endpoint

@PostMapping("/upload")
public AjaxResult uploadProfile(MultipartFile file) {
  try {
    String path = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file);
    path = path.replaceAll("//", "/");
    return AjaxResult.success("success", path);
  } catch (Exception e) {
    e.printStackTrace();
    return AjaxResult.error("Upload failed");
  }
}

The endpoint receives the MultipartFile, stores it, and returns a static path accessible to the front‑end.

Key plugin properties

img : source image URL (url, base64, or blob). Default: empty.

outputSize : quality of the generated image (0.1‑1). Default: 1.

outputType : format of the generated image (jpeg, png, webp). Default: jpg.

info : show crop‑box size info (true/false). Default: true.

canScale : allow mouse‑wheel scaling (true/false). Default: true.

autoCrop : generate a default crop box (true/false). Default: false.

autoCropWidth / autoCropHeight : default crop‑box dimensions (default 80% of container).

fixedBox : lock the crop‑box size (true/false). Default: false.

fixed : enforce a fixed aspect ratio (true/false). Default: true.

fixedNumber : aspect‑ratio array, e.g., [1,1]. Default: [1,1].

full : output image with original aspect ratio (true/false). Default: false.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

VueSpringBootimage uploadcroppingElementUIvue-cropper
The Dominant Programmer
Written by

The Dominant Programmer

Resources and tutorials for programmers' advanced learning journey. Advanced tracks in Java, Python, and C#. Blog: https://blog.csdn.net/badao_liumang_qizhi

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.