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.
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-cropperImporting 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
