wordpress个人展示网站6,新西兰网站后缀,珠海自适应网站,做个什么样的网站文章目录 基本介绍术语介绍图片上传方式介绍普通上传用户直传应用服务器签名后直传 OSS对象存储后端实现maven配置文件配置类ServiceController 图片上传前端图片上传组件api页面使用组件组件效果 基本介绍
术语介绍
Bucket#xff08;存储空间#xff09;#xff1a;用于… 文章目录 基本介绍术语介绍图片上传方式介绍普通上传用户直传应用服务器签名后直传 OSS对象存储后端实现maven配置文件配置类ServiceController 图片上传前端图片上传组件api页面使用组件组件效果 基本介绍
术语介绍
Bucket存储空间用于存储对象的容器所有对象都属于某个存储空间中一般是一个项目创建一个Bucket来专门存储该项目的文件Object对象可以理解为文件对象在Bucket内部由唯一的Key来标识Region地域选择数据所存放的物理地址如北京Endpoint访问域名对外服务的访问域名不同Region的域名不同通过内网和外网访问相同Region的域名也不同AccessKey访问密钥简称AK指的是身份验证中使用的AccessKeyId和AccessKeySecret
图片上传方式介绍
普通上传 描述用户现在客户端将文件上传到应用所部署的服务器然后服务器再将文件上传到OSS中OSS存储文件之后返回文件地址给应用服务器应用服务器接着将文件地址存储到数据库中。后续需要访问文件直接从数据库中查询出访问地址然后直接访问即可。 缺点需要将文件上传至应用服务器消耗应用服务器的资源应用服务器压力大
用户直传
描述直接将OSS的相关密钥存储到js中直接使用js方法上传文件用户直接在客户端就将文件上传到OSS 缺点不安全密钥容易被获取不法分子可能会恶意刷流量没办法限流
应用服务器签名后直传 描述客户端向应用服务器获取签名然后凭借签名直接将文件上传到OSS 优点安全且节省应用服务器性能
OSS对象存储后端实现
maven
dependencygroupIdcom.aliyun.oss/groupIdartifactIdaliyun-sdk-oss/artifactIdversion 3.10.2/version
/dependency配置文件 oss.accessKeyId你的accessKeyId
oss.accessKeySecret你的accessKeySecret
oss.endpoint你的域名
oss.bucketName你的存储空间配置类
用来加载配置文件里面的配置创建OSS对象并创建Bean
package com.shm.config;import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;Configuration
public class OSSConfig {Value(${oss.endpoint})private String endpoint;Value(${oss.accessKeyId})private String accessKeyId;Value(${oss.accessKeySecret})private String accessKeySecret;Beanpublic OSS ossClient() {return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);}
}
Service
【接口】
package com.shm.service;import com.ruoyi.common.core.domain.AjaxResult;
import org.springframework.stereotype.Service;public interface OssService {/*** 获取签名* return*/public AjaxResult getPolicy();
}
【实现类】
package com.shm.service.impl;import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.ruoyi.common.core.domain.AjaxResult;
import com.shm.service.OssService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;Service
public class OssServiceImpl implements OssService {Autowiredprivate OSS ossClient;Value(${oss.bucketName})private String bucketName;Value(${oss.endpoint})private String endpoint;Value(${oss.accessKeyId})private String accessId;Overridepublic AjaxResult getPolicy() {// 拼接出Host地址String host https:// bucketName . endpoint;MapString, String respMap null;try {/// 设置过期时间// 秒数这里设置10秒就过期long expireTime 10;long expireEndTime System.currentTimeMillis() expireTime * 1000;Date expiration new Date(expireEndTime);/// 指定请求的条件PolicyConditions policyConditions new PolicyConditions();// 设置内容长度允许的字节数最大是1048576000个字节1MB1048576个字节这里限制最大是100MBpolicyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 104857600);// 限制上传文件的前缀// 设置文件夹这里按照日期分文件夹String dir new SimpleDateFormat(yyyy-MM-dd).format(new Date()) /;policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);/// 生成policyString postPolicy ossClient.generatePostPolicy(expiration, policyConditions);byte[] binaryData postPolicy.getBytes(utf-8);String encodedPolicy BinaryUtil.toBase64String(binaryData);String postSignature ossClient.calculatePostSignature(postPolicy);respMap new LinkedHashMapString, String();respMap.put(accessId, accessId);respMap.put(policy, encodedPolicy);respMap.put(signature, postSignature);respMap.put(dir, dir);respMap.put(host, host);respMap.put(expire, String.valueOf(expireEndTime / 1000));} catch (Exception e) {System.out.println(e.getMessage());}return AjaxResult.success(获取凭证成功, respMap);}
}
Controller
package com.shm.controller;import com.ruoyi.common.core.domain.AjaxResult;
import com.shm.service.OssService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;RestController
RequestMapping(/thirdParty/oss)
Api(OssController)
public class OssController {Autowiredprivate OssService ossService;ApiOperation(获取OSS凭证)GetMapping(/policy)PreAuthorize(ss.hasPermi(thirdParty:oss:policy))public AjaxResult policy() {return ossService.getPolicy();}
}
图片上传前端
图片上传组件
该组件基于若依管理系统前端项目所提供的图片上传组件修改原组件采用直传方式改动后采用签名后直传的方式
templatediv classcomponent-upload-imageel-uploadmultiple:actionuploadImgUrl:datadataObjlist-typepicture-card:on-successhandleUploadSuccess:before-uploadhandleBeforeUpload:limitlimit:on-errorhandleUploadError:on-exceedhandleExceedrefimageUpload:before-removehandleDelete:show-file-listtrue:headersheaders:file-listfileList:on-previewhandlePictureCardPreview:class{ hide: fileList.length limit }el-icon classavatar-uploader-iconplus//el-icon/el-upload!-- 上传提示 --div classel-upload__tip v-ifshowTip请上传template v-iffileSize大小不超过 b stylecolor: #f56c6c{{ fileSize }}MB/b/templatetemplate v-iffileType格式为 b stylecolor: #f56c6c{{ fileType.join(/) }}/b/template的文件/divel-dialogv-modeldialogVisibletitle预览width800pxappend-to-bodyimg:srcdialogImageUrlstyledisplay: block; max-width: 100%; margin: 0 auto//el-dialog/div
/templatescript setup
import {getToken} from /utils/auth;
import ossApi from /api/thirdParty/oss
import uuidApi from /utils/uuidconst props defineProps({modelValue: [String, Object, Array],// 图片数量限制limit: {type: Number,default: 5,},// 大小限制(MB)fileSize: {type: Number,default: 5,},// 文件类型, 例如[png, jpg, jpeg]fileType: {type: Array,default: () [png, jpg, jpeg],},// 是否显示提示isShowTip: {type: Boolean,default: true},
});const {proxy} getCurrentInstance();
const emit defineEmits();
const number ref(0);
const uploadList ref([]);
const dialogImageUrl ref();
const dialogVisible ref(false);
const baseUrl import.meta.env.VITE_APP_BASE_API;
const uploadImgUrl ref(import.meta.env.VITE_APP_OSS_PATH); // 上传的图片服务器地址
const headers ref({Authorization: Bearer getToken()});
const fileList ref([]);
const showTip computed(() props.isShowTip (props.fileType || props.fileSize)
);
let dataObj {policy: ,signature: ,key: ,OSSAccessKeyId: ,dir: ,host:
};watch(() props.modelValue, val {if (val) {// 首先将值转为数组const list Array.isArray(val) ? val : props.modelValue.split(,);console.log(list: JSON.stringify(list));// 然后将数组转为对象数组fileList.value list.map(item {if (typeof item string) {item {url: item};}return item;});console.log(fileList: JSON.stringify(fileList));} else {fileList.value [];return [];}
}, {deep: true, immediate: true});// 上传前loading加载
function handleBeforeUpload(file) {let isImg false;if (props.fileType.length) {let fileExtension ;if (file.name.lastIndexOf(.) -1) {fileExtension file.name.slice(file.name.lastIndexOf(.) 1);}isImg props.fileType.some(type {if (file.type.indexOf(type) -1) return true;if (fileExtension fileExtension.indexOf(type) -1) return true;return false;});} else {isImg file.type.indexOf(image) -1;}if (!isImg) {proxy.$modal.msgError(文件格式不正确, 请上传${props.fileType.join(/)}图片格式文件!);return false;}if (props.fileSize) {const isLt file.size / 1024 / 1024 props.fileSize;if (!isLt) {proxy.$modal.msgError(上传头像图片大小不能超过 ${props.fileSize} MB!);return false;}}//获取OSS签名return new Promise((resolve, reject) {ossApi.getPolicy().then((response) {console.log(policy response: JSON.stringify(response))// debugger;dataObj.policy response.data.policydataObj.signature response.data.signaturedataObj.OSSAccessKeyId response.data.accessIddataObj.key response.data.dir uuidApi.getUUID() _${filename}dataObj.dir response.data.dirdataObj.host response.data.hostconsole.log(获取policy成功)// console.log(dataObj: JSON.stringify(dataObj))// console.log(uploadImgUrl: import.meta.env.VITE_APP_OSS_PATH)proxy.$modal.loading(正在上传图片请稍候...);number.value;resolve(true)}).catch((err) {console.log(获取policy失败)reject(false)})})}// 文件个数超出
function handleExceed() {proxy.$modal.msgError(上传文件数量不能超过 ${props.limit} 个!);
}// 上传成功回调
function handleUploadSuccess(res, file) {console.log(handleUploadSuccess JSON.stringify(res) JSON.stringify(file))uploadList.value.push({name: file.name, url: dataObj.host / dataObj.key.replace(${filename}, file.name)});console.log(上传成功)uploadedSuccessfully();
}// 删除图片
function handleDelete(file) {const findex fileList.value.map(f f.name).indexOf(file.name);if (findex -1 uploadList.value.length number.value) {fileList.value.splice(findex, 1);let urlList getUrlList(fileList);emit(update:modelValue, urlList);return false;}
}// 上传结束处理
function uploadedSuccessfully() {console.log(number.value: number.value);if (number.value 0 uploadList.value.length number.value) {//将新上传的图片添加到fileListfor (let i 0; i uploadList.value.length; i) {fileList.value.push(uploadList.value[i]);}//将所有图片的url拿出来形成一个集合let urlList getUrlList(fileList);uploadList.value [];number.value 0;emit(update:modelValue, urlList);proxy.$modal.closeLoading();}
}// 上传失败
function handleUploadError() {proxy.$modal.msgError(上传图片失败);proxy.$modal.closeLoading();
}// 预览
function handlePictureCardPreview(file) {dialogImageUrl.value file.url;dialogVisible.value true;
}function getUrlList(fileList) {let urlList [];for (let i 0; i fileList.value.length; i) {urlList.push(fileList.value[i].url);}return urlList;
}/scriptstyle scoped langscss
// .el-upload--picture-card 控制加号部分
:deep(.hide .el-upload--picture-card) {display: none;
}
/style下面的代码即去配置文件中读取图片上传地址我使用读取配置的方式主要是为了方便部署时的环境切换也可以直接写在组件里面打包部署时修改会繁琐一点也会容易遗忘
const uploadImgUrl ref(import.meta.env.VITE_APP_OSS_PATH); // 上传的图片服务器地址下面的代码的作用是将值同步给组件v-model所绑定的变量中
emit(update:modelValue, urlList);api
【OSS请求API】
import request from /utils/request/*
菜单管理相关的API请求函数
*/
const api_name /thirdParty/ossexport default {getPolicy(data) {return request({url: ${api_name}/policy,method: get,params: data})},}【oss生成API】
/*** 获取uuid*/
export default {getUUID() {return xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx.replace(/[xy]/g, c {return (c x ? (Math.random() * 16 | 0) : (r0x3 | 0x8)).toString(16)})}
}使用UUID的作用主要是用户上传的图片名称可能一样但是图片内容不同在名称前面添加UUID可以避免文件名冲突如下图
页面使用组件 使用通过v-model绑定变量值的形式是url数组。limit1的作用是限制只能上传一张图片
imageUpload v-modelform.logo limit1/imageUpload查看组件的代码limit fileSize fileType isShowTip这个值都是可以设置的具体的含义请查看下图
组件效果
这个组件的功能还是比较完善的具体效果可以查看下面的效果图 【上传图片之前】 【上传图片成功后】 【上传成功的图片可以预览和删除】 【预览效果】 【上传多个图片的效果】