1.配置oss
步骤1:ruoyi-admin-resources-application.yml
模板如下
#oss配置 xxx你自己的对应信息
aliyun:
oss:
endpoint: https://oss-cn-hangzhou.aliyuncs.com # 阿里云 OSS的endpoint
accessKeyId: xxxx # 阿里云 AccessKey ID
accessKeySecret: xxxxx # 阿里云 AccessKey Secret
bucketName: xxxxxxx # OSS存储桶名称
fileUploadDir: xxxxxxxx # 上传文件保存的目录
步骤2:pom.xml添加依赖
ruoyi-admin\ruoyi-common\ (两个文件都要加)
<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>
2.实现工具类
在ruoyi-common模块下utils添加工具类AvatarUpLoadUtil
我是用memberId加一些其他数据确保存储路径的唯一性,可以更改,但是byte[] fileBytes不能少,它是用来存储文件处理后的字符流
package com.ruoyi.common.utils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.PutObjectRequest;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.*;
/**
* 头像Oss服务调用
*/
@Log4j2
@Service
public class AvatarUpLoadUtil { // 上传文件到阿里云 OSS
@Value("${aliyun.oss.endpoint}")
public String endpoint;
@Value("${aliyun.oss.accessKeyId}")
public String accessKeyId;
@Value("${aliyun.oss.accessKeySecret}")
public String accessKeySecret;
@Value("${aliyun.oss.bucketName}")
public String bucketName;
@Value("${aliyun.oss.fileUploadDir}")
public String fileUploadDir;
// 图片上传
public String uploadFileToOSS(byte[] fileBytes, String memberId ,String avatar) throws IOException {
// 创建 OSSClient 实例
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// 创建字节流输入流
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(fileBytes);
// 设置文件名,可以使用文本内容生成唯一文件名,避免重名
String objectName = "memberAvatar/" + memberId.hashCode() + ".jpg";
// 构造上传请求
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, byteArrayInputStream);
// 上传文件
ossClient.putObject(putObjectRequest);
System.out.println("File uploaded successfully to OSS.");
// 去掉 endpoint 中的 https:// 前缀,确保不会重复添加
String fileUrl = "https://" + bucketName + "." + endpoint.replace("https://", "") + "/" + objectName;
return fileUrl;
} catch (Exception e) {
e.printStackTrace();
throw new IOException("Error uploading file to OSS: " + e.getMessage());
} finally {
// 关闭 OSSClient
ossClient.shutdown();
}
}
}
3.修改后端代码
domain
添加存储类型MultipartFile的avatarFile,用于接收上传的文件,但不映射到数据库
controller
因为若依请求后面mapper和service层等都是使用信息整体进行操作,所以我就在controller对数据进行了拆开,然后统一,代替了 MemberInfo memberInfo
ps:有一点繁琐(害羞),应该可以简便一下的
因为要文件和其他数据一起发送使用的是multipart/form-data
编码方式,所以后端使用的是@RequestParam注解
multipart/form-data
是一种用于发送文件和其他数据的 HTTP 表单数据编码方式,而 @RequestParam
是 Spring MVC 中用于获取请求参数的注解。它们常常一起使用,尤其是在处理文件上传的场景中。
注意 修改不意味着必须修改头像就是说文件可能为空!!!!!!!
ServiceImpl
在return之前
1.处理文件变成字符流
2.将oss存储url路径替换本来错误的路径
ps:readAllBytes()只能Java 9及以上才能使用
@Override
public int insertMemberInfo(MemberInfo memberInfo)
{
if (memberInfo.getAvatarFile() != null && !memberInfo.getAvatarFile().isEmpty()) {
// 上传头像文件并获取文件 URL
try (InputStream inputStream = memberInfo.getAvatarFile().getInputStream()) {
// 读取图片的字节数据
byte[] fileBytes = inputStream.readAllBytes();
// 调用上传方法
String pictureUrl = avatarUploadUtil.uploadFileToOSS(fileBytes, memberInfo.getMemberId(),memberInfo.getPictureUrl());
// 将文件 URL 存储到数据库中
memberInfo.setPictureUrl(pictureUrl);
System.out.println("头像上传成功");
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("图片上传失败: " + e.getMessage(), e);
}
}
return memberInfoMapper.insertMemberInfo(memberInfo);
}
Java 8 兼容代码(没有使用过,不确定,存档给未来的自己,应该没什么问题(思考))
try (InputStream inputStream = memberInfo.getAvatarFile().getInputStream()) {
// 使用 ByteArrayOutputStream 来收集字节数据
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
}
// 获取字节数组
byte[] fileBytes = byteArrayOutputStream.toByteArray();
}
同上 修改操作 可能不动头像 需要判断
4.修改前端代码
思路:通过el-upload组件的on-change拿到文件临时的url地址和文件,然后再赋值给两个formdata表单中的pictureUrl和avatarFile变量,虽然刷新就消失了,但是这正是不点击提交按钮就不添加的效果嘛
el组件
表单
因为要上传文件,所以我用了formData
FormData
是一个浏览器原生的 API,专门用于构造可以提交到服务器的表单数据,特别适合处理包含二进制文件(如图片、视频等)的表单。
方法
1. beforeAvatarUpload
文件处理一下()
/** 上传前的处理 */
beforeAvatarUpload(file) {
const isImage = file.type.startsWith("image/");
const isLt80M = file.size / 1024 / 1024 < 80; // 限制文件大小为 80MB
if (!isImage) {
this.$message.error("上传的文件必须是图片格式!");
}
if (!isLt80M) {
this.$message.error("上传的图片大小不能超过 80MB!");
}
if (this.avatarList.length >= 1) {
this.$message.error("只允许上传一张图片!");
return false; // 阻止上传
}
return isImage && isLt80M;
},
2. handleAvatarChange()
拿到两个数据
/** 图片变化时的处理函数 */
handleAvatarChange(file) {
// 使用 URL.createObjectURL 来创建本地 URL
this.formData.pictureUrl = URL.createObjectURL(file.raw); // 获取本地图片 URL
this.formData.avatarFile = file.raw; // 保存文件内容
},
3. submitForm()
提交 我们要动态处理avatarFile 新增有,修改不一定有
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
console.log("formDta")
console.log(this.formData)
console.log(this.formData.memberId)
// 创建 FormData 对象
const formData = new FormData();
// 动态处理 avatarFile
if (this.formData.avatarFile instanceof File) {
formData.append('avatarFile', this.formData.avatarFile);
}
// 将表单中的其他数据添加到 FormData
formData.append('memberId',this.formData.memberId)
formData.append('name', this.formData.name);
formData.append('major', this.formData.major);
formData.append('joinTime', this.formData.joinTime);
formData.append('expertise', this.formData.expertise);
formData.append('employmentCompany', this.formData.employmentCompany);
formData.append('phone', this.formData.phone);
formData.append('pictureUrl',this.formData.pictureUrl)
if (valid) {
if (this.formData.memberId != null) {
updateInfo(this.formData).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addInfo(this.formData).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
请求
加一个headers,确保前端传入后端数据是'multipart/form-data' 编码方式
// 修改研发团队成员展示
export function updateInfo(data) {
return request({
url: '/RDTeam/info',
method: 'put',
data: data,
headers: {
'Content-Type': 'multipart/form-data' // 手动设置 Content-Type
}
})
}
新增应该一样,复制粘贴后端修改代码应该就行了
然后然后就结束了(撒花)
本博客是一次记录,不确定有没有错,可能有没发现的错误(祈祷没有),但是目前可以实现。