文章目錄
- 說明
- SSM使用
- 引入依賴
- 在spring-mvc.xml中加入配置
- 創建上傳工具類AliOssUtil
- 響應工具類ResultJSON
- 編寫controller
- 自動上傳
- 代碼編寫
- 結果如下演示
- 手動上傳
- 前端代碼編寫
- 后端代碼編寫
- 結果演示如下
說明
為了方便演示,前后端代碼一起寫了
關于對象存儲請看我另一篇博客
阿里云對象存儲OSS的使用
SSM使用
引入依賴
<!--阿里云OSS依賴--><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.17.4</version></dependency><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version></dependency><dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>1.1.1</version></dependency><!-- no more than 2.3.3--><dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId><version>2.3.3</version></dependency><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency>
在spring-mvc.xml中加入配置
<!-- 配置 MultipartResolver 用于文件上傳 --><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 設置最大上傳文件大小 --><property name="maxUploadSize" value="10485760"/> <!-- 10MB --><property name="maxInMemorySize" value="4096"/><property name="defaultEncoding" value="UTF-8"/></bean>
創建上傳工具類AliOssUtil
package com.Teenage_education_network.utils;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;import java.io.InputStream;public class AliOssUtil {private static final String ENDPOINT = "https://oss-cn-beijing.aliyuncs.com";private static final String ACCESS_KEY_ID = "你的id";private static final String SECRET_ACCESS_KEY = "你的秘鑰";private static final String BUCKET_NAME = "項目名";/** uploadFile方法* objectName:文件名稱比如 "YEjdihp893bif1.jpg"* inputStream:文件流,用于讀取文件比如,D:\Users\Administrator\Desktop\YEjdihp893bif1.jpg* *///上傳文件,返回文件的公網訪問地址public static String uploadFile(String objectName, InputStream inputStream){// 創建OSSClient實例。OSS ossClient = new OSSClientBuilder().build(ENDPOINT,ACCESS_KEY_ID,SECRET_ACCESS_KEY);//公文訪問地址String url = "";try {// 創建存儲空間。ossClient.createBucket(BUCKET_NAME);ossClient.putObject(BUCKET_NAME, objectName, inputStream);// 這里是返回阿里云的url地址url = "https://"+BUCKET_NAME+"."+ENDPOINT.substring(ENDPOINT.lastIndexOf("/")+1)+"/"+objectName;} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}return url;}
}
響應工具類ResultJSON
package com.hsh.pojo.tdo;import java.io.Serializable;/*** @Author: wzy* @Date: 2024/11/13 11:03* @Description: 返回結果類*/
public class ResultJSON<T> implements Serializable {private Integer code;private String msg;private T data;public ResultJSON(Integer code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;}/*** 操作成功或者失敗* @param c 受影響行數* @return 當前傳入的受影響行數>0則返回成功,否則返回失敗*/public static ResultJSON successORerror(int c){return c>0?new ResultJSON(200,"操作成功",c):new ResultJSON(400,"操作失敗",c);}public static ResultJSON success(){return new ResultJSON(200,"操作成功",null);}public static ResultJSON success(String msg){return new ResultJSON(200,msg,null);}public static <T> ResultJSON success(T data){return new ResultJSON(200,"操作成功",data);}public static ResultJSON success(Integer code,String msg){return new ResultJSON(code,msg,null);}public static <T> ResultJSON success(String msg,T data){return new ResultJSON(200,msg,data);}public static <T> ResultJSON success(Integer code,String msg,T data){return new ResultJSON(code,msg,data);}public static ResultJSON error(){return new ResultJSON(500,"操作失敗",null);}public static ResultJSON error(String msg){return new ResultJSON(500,msg,null);}public static ResultJSON error(Integer code,String msg){return new ResultJSON(code,msg,null);}public T getData() {return data;}public void setData(T data) {this.data = data;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}
編寫controller
package com.hsh.controller;import com.hsh.pojo.tdo.ResultJSON;
import com.hsh.utils.AliOssUtil;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.util.UUID;/*** @author xrkhy* @date 2025/9/6 19:05* @description*/@RestController
@RequestMapping("/upload")
public class UploadController {// 本次請求通過elementPlus的el-upload組件上傳圖片,通過el-upload組件的屬性發起請求// 前端上傳路徑action="/api/upload/imgUpload" 要和后端一致 這里的/api是前端的反向代理的標識// 前端的name="img" 是這里的形參名// 前端的請求頭添加token :headers="{'Authorization':tokenStore.token}"@PostMapping("/imgUpload")public ResultJSON<String> imgUpload(@RequestParam("img") MultipartFile img) throws IOException {System.out.println(img);if (img == null || img.isEmpty()) {// 處理文件為空的情況return ResultJSON.error("文件不能為空");}String originalFilename = img.getOriginalFilename();// 生成新的唯一的文件名String fileNmae = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));String url = AliOssUtil.uploadFile(fileNmae, img.getInputStream());System.out.println(url);return ResultJSON.success("添加成功",url);}
}
自動上傳
代碼編寫
<template><el-form:model="productForm"label-width="120px"label-position="right"><!-- 用戶基礎信息 --><el-form-item label="商品名稱" prop="productName"><el-input v-model="productForm.productName"></el-input></el-form-item><el-form-item label="封面圖片"><!-- :auto-upload 設置是否自動上傳 true自動上傳 --><!-- action為你的請求路徑:你要替換為你的上傳API地址 --><!-- name: 上傳的文件字段名 (也就是后端的參數 我這里是img)后端的接收參數如下就是我上面寫的UploadControllerpublic ResultJSON<String> imgUpload(@RequestParam("img") MultipartFile img){}--><!-- :on-success="handleAvatarSuccess" 上傳成功回調 --><!-- :before-upload="beforeAvatarUpload"上傳前校驗 --><!-- list-type="picture-card" 文件列表的類型 這里不需要因為已經有<i class="el-icon-plus" v-if="!productForm.imageUrl"></i>代替了--><!-- :show-file-list="false" 是否顯示已上傳文件列表 --><!-- 除了上面還可以設置響應頭,配置如下:headers="{'Authorization':tokenStore.token}"--><el-upload:auto-upload="true"action="http://localhost:8080/upload/imgUpload"name="img":on-success="handleAvatarSuccess":before-upload="beforeAvatarUpload":show-file-list="false"><!-- v-if="!productForm.imageUrl" 是如果上傳成功這個+圖標(<i class="el-icon-plus"></i>)上傳的提示就不顯示了 --><istyle="font-size: 20px; border: 1px solid #ccc; padding: 20px"class="el-icon-plus"v-if="!productForm.imageUrl"></i><img style="width: 100px" v-else :src="productForm.imageUrl" /></el-upload></el-form-item><el-form-item label="商品價格" prop="productPrice"><el-input-numberv-model="productForm.productPrice":precision="2":step="0.01"></el-input-number></el-form-item><el-form-item label="商品庫存" prop="productStock"><el-input-numberv-model="productForm.productStock"label="描述文字"></el-input-number></el-form-item><!-- 操作按鈕 --><el-form-item><el-button type="primary" @click="submitForm">提交</el-button><el-button @click="resetForm">重置</el-button></el-form-item></el-form>
</template><script>
export default {data() {return {productForm: {productId: null,productName: "",imageUrl: "",productPrice: "",productStock: ""},}}methods: {// 上傳成功后的回調handleAvatarSuccess(res, file) {this.productForm.imageUrl = res.data;},// 上傳前的校驗beforeAvatarUpload(file) {const isJPG = file.type === "image/jpeg" || file.type === "image/png";const isLt2M = file.size / 1024 / 1024 < 2;if (!isJPG) {this.$message.error("上傳頭像圖片只能是 JPG 或 PNG 格式!");}if (!isLt2M) {this.$message.error("上傳頭像圖片大小不能超過 2MB!");}return isJPG && isLt2M;},submitForm() {console.log("提交的數據:", this.formData);// 這里在發起請求},}
}
</script>
結果如下演示
上面數據確實是拿到了,此時在點擊提交發送。
手動上傳
前端代碼編寫
<template><div><h1>圖片手動提交</h1><el-form:model="productForm"style="width: 500px"label-width="120px"label-position="right"><!-- 用戶基礎信息 --><el-form-item label="商品名稱" prop="productName"><el-input v-model="productForm.productName"></el-input></el-form-item><el-form-item label="封面圖片"><!-- :auto-upload 設置是否自動上傳 true自動上傳 --><!-- action為你的請求路徑:你要替換為你的上傳API地址 --><!-- list-type="picture-card" 文件列表的類型 這里不需要因為已經有<i class="el-icon-plus" v-if="!productForm.imageUrl"></i>代替了--><!-- :show-file-list="false" 是否顯示已上傳文件列表 這里關閉 --><!-- v-if="!productForm.imageUrl" 是如果上傳成功這個+圖標(<i class="el-icon-plus"></i>)上傳的提示就不顯示了 --><el-upload:auto-upload="false"action="#":show-file-list="false":on-change="handleImgChange"><istyle="font-size: 20px; border: 1px solid #ccc; padding: 20px"class="el-icon-plus"v-if="!productForm.imageUrl"></i><img style="width: 100px" v-else :src="productForm.imageUrl" /></el-upload><!-- v-if="productForm.imageUrl" 如果圖片不存在 img不顯示 --><!-- <img v-if="imgURL" :src="imgURL" /> --></el-form-item><el-form-item label="商品價格" prop="productPrice"><el-input-numberv-model="productForm.productPrice":precision="2":step="0.01"></el-input-number></el-form-item><el-form-item label="商品庫存" prop="productStock"><el-input-numberv-model="productForm.productStock"label="描述文字"></el-input-number></el-form-item><!-- 操作按鈕 --><el-form-item><el-button type="primary" @click="submitForm">提交</el-button></el-form-item></el-form></div>
</template><script>
import axios from "axios";export default {name: "ImageUpload",data() {return {// 表單數據// 注意這里表單不能有字段為null,否則會報錯// 比如productId: null, 發送給后端報錯productForm: {productId: "",productName: "",imageUrl: "",productPrice: "",productStock: "",imgUrlFile: ""}};},methods: {// handleFileChange(file, fileList) {// this.fileList = fileList;// },// 提交前實現封面圖片預覽handleImgChange(uploadFile) {// 預覽圖片// this.imgUrl = URL.createObjectURL(uploadFile.raw);this.productForm.imageUrl = URL.createObjectURL(uploadFile.raw);console.log(this.productForm.imageUrl);this.productForm.imgUrlFile = uploadFile.raw;// this.productForm.imageUrl = uploadFile.raw;},async submitForm() {const formData = new FormData();// 追加其他表單字段// 遍歷 productForm 對象的屬性for (const key in this.productForm) {// 將每個屬性和值添加到 FormData 中formData.append(key, this.productForm[key]);}// 追加文件字段formData.append("file", this.imgUrlFile);this.clgFromData(formData);const res = await axios.post("http://localhost:8080/product/addProductWithImg",formData// 下面的headers可以不,會自動識別是json還是formdata// {// headers: {// "Content-Type": "multipart/form-data"// }// });console.log(res);},clgFromData(formData) {for (let pair of formData.entries()) {console.log(pair[0] + ", " + pair[1]);}}}
};
</script><style scoped></style>
后端代碼編寫
package com.hsh.controller;import com.hsh.pojo.Product;
import com.hsh.pojo.tdo.ResultJSON;
import com.hsh.service.ProductService;
import com.hsh.utils.AliOssUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.util.List;
import java.util.UUID;@RestController
@RequestMapping("/product")
@CrossOrigin(origins = "http://localhost:8081")
public class ProductController {@AutowiredProductService productService;@PostMapping("/addProduct")public ResultJSON addProduct(@RequestBody Product product){System.out.println("product = " + product);return productService.addProduct(product);}// 注意 傳入的product對象的屬性不能是 null 也不能是 MultipartFile,否則報400的錯誤// 注意:java的product對象中,沒有imgUrlFile屬性。// 前端傳入的product對象中,imgUrlFile屬性是MultipartFile類型。// 下面的@RequestParam也可換成@RequestPart注解@PostMapping("/addProductWithImg")public ResultJSON<Product> findProductById(@ModelAttribute Product product,@RequestParam(value = "imgUrlFile",required = false) MultipartFile imgUrlFile) throws IOException {System.out.println("product = " + product);System.out.println("imgFile = " + imgUrlFile);if (imgUrlFile == null || imgUrlFile.isEmpty()) {// 處理文件為空的情況return ResultJSON.error("文件不能為空");}String originalFilename = imgUrlFile.getOriginalFilename();// 生成新的唯一的文件名String fileNmae = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));String url = AliOssUtil.uploadFile(fileNmae, imgUrlFile.getInputStream());System.out.println(url);product.setImageUrl(url);return productService.addProduct(product);}}