记录springboot+vue实现图片上传OSS功能
-
阿里云OSS
-
springboot实现图片上传
-
vue实现程序头像上传的功能
阿里云OSS
开通
登录注册
选择开通 这个是按照流量计费的
创建 Bucket
获取AccessKey ID 和 AccessKey Secret 备用
创建springboot 工程项目 service-oss
创建配置文件 application.properties
#服务端口
server.port=8002
#服务名
spring.application.name=service-oss
#环境设置:dev、test、prod
spring.profiles.active=dev
#阿里云 OSS
#不同的服务器,地址不同
aliyun.oss.file.endpoint=oss-cn-beijing.aliyuncs.com
aliyun.oss.file.keyid=LTAIXu4ab7KQym
aliyun.oss.file.keysecret=jTah9kfhqJcjVrJY1MCxJWMUgZK
#bucket可以在控制台创建,也可以使用java代码创建
aliyun.oss.file.bucketname=在阿里云创建的Bucket 名称
pom.xml文件引入依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
创建启动类 OssApplication
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan(basePackages = {"com.education"})
public class OssApplication {
public static void main(String[] args) {
SpringApplication.run(OssApplication.class, args);
}
}
创建util文件夹下创建常量类ConstantPropertiesUtil 读取配置文件
package com.education.oss.util;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @Author: Gosin
* @Date: 2022/2/16 14:47
* 读取配置文件的值
*/
@Component
public class ConstantPropertiesUtil implements InitializingBean {
//读取配置文件的内容
@Value("${aliyun.oss.file.endpoint}")
private String endpoint;
@Value("${aliyun.oss.file.keyid}")
private String keyId;
@Value("${aliyun.oss.file.keysecret}")
private String keySecret;
@Value("${aliyun.oss.file.bucketname}")
private String bucketname;
//静态常量
public static String END_POINT;
public static String ACCESS_KEY_ID;
public static String ACCESS_KEY_SECRET;
public static String BUCKET_NAME;
@Override
public void afterPropertiesSet() throws Exception {
END_POINT = endpoint;
ACCESS_KEY_ID = keyId;
ACCESS_KEY_SECRET = keySecret;
BUCKET_NAME = bucketname;
}
}
创建controller文件夹 并创建OssController 类
@RestController//交给spring管理 返回数据
@RequestMapping("eduoss")
@CrossOrigin//跨域
public class OssController {
@Autowired
private OssService ossService;
//上传头像的方法
@ApiOperation(value = "文件上传")
@PostMapping(("upload"))
public R uploadOssFile(MultipartFile file){
//获取上传文件 MultipartFile
String url = ossService.upload(file);
return R.ok().data("url",url);
}
}
创建service文件夹 并创建OssService方法和impl文件夹
public interface OssService {
String upload(MultipartFile file);
}
impl文件夹下创建OssServiceImpl 类
@Service
public class OssServiceImpl implements OssService {
@Override
public String upload(MultipartFile file) {
String url = null;
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = ConstantPropertiesUtil.END_POINT;
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = ConstantPropertiesUtil.ACCESS_KEY_ID;
String accessKeySecret = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
// 填写Bucket名称,例如examplebucket。
String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
// 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
// String objectName = "exampledir/exampleobject.txt";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
// String filePath= "D:\\localpath\\examplefile.txt";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
InputStream inputStream = file.getInputStream();
String fileName = file.getOriginalFilename();
//1.随机唯一值 防止文件名重复
String uuid = UUID.randomUUID().toString().replaceAll("-","");
fileName = uuid+fileName;
//2.通过时间格式创建文件路径 保存文件
String datapath = new DateTime().toString("yyyy/MM/dd");
fileName = datapath+"/"+fileName;
// 创建PutObject请求。
ossClient.putObject(bucketName, fileName, inputStream);
url = "http://"+bucketName+"."+endpoint+"/"+fileName;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
return url;
}
}
前端整合图片上传组件 只提供上传图片部分代码片段
从模板中复制组件ImageCropper文件夹和PanThumb文件夹到components文件夹下
添加文件上传组件
<!-- 讲师头像 -->
<el-form-item label="讲师头像">
<!-- 头衔缩略图 -->
<pan-thumb :image="teacher.avatar"/>
<!-- 文件上传按钮 -->
<el-button type="primary" icon="el-icon-upload" @click="imagecropperShow=true">更换头像
</el-button>
<!--
v-show:是否显示上传组件
:key:类似于id,如果一个页面多个图片上传控件,可以做区分
:url:后台上传的url地址
@close:关闭上传组件
@crop-upload-success:上传成功后的回调 -->
<image-cropper
v-show="imagecropperShow"
:width="300"
:height="300"
:key="imagecropperKey"
:url="BASE_API+'/eduoss/upload/'"//java程序中上传图片的方法路径
field="file"
@close="close"
@crop-upload-success="cropSuccess"/>
</el-form-item>
使用组件 在data(){}中定义变量和初始值
// 保存按钮是否禁用,
saveBtnDisabled: false,
BASE_API: process.env.BASE_API, // 接口API地址
imagecropperShow: false, // 是否显示上传组件
imagecropperKey: 0 // 上传组件id
引入组件和组件声明
//引入组件
import ImageCropper from '@/components/ImageCropper'
import PanThumb from '@/components/PanThumb'
export default {
components:{ImageCropper,PanThumb},//声明组件
编写close()方法和cropSuccess()方法
methods: {
close(){//上传关闭弹框的方法
this.imagecropperShow=false;
this.imagecropperKey = this.imagecropperKey+1
},
cropSuccess(data){//上传成功的方法
this.imagecropperShow=false;
//上传完后返回图片地址
this.teacher.avatar = data.url
this.imagecropperKey = this.imagecropperKey+1
},
完整的代码结构仅供参考
<template>
<div class="app-container">
讲师添加
<el-form label-width="120px">
<el-form-item label="讲师名称">
<el-input v-model="teacher.name"/>
</el-form-item>
<el-form-item label="讲师排序">
<el-input-number v-model="teacher.sort" controls-position="right" min="0"/>
</el-form-item>
<el-form-item label="讲师头衔">
<el-select v-model="teacher.level" clearable placeholder="请选择">
<!--
数据类型一定要和取出的json中的一致,否则没法回填
因此,这里value使用动态绑定的值,保证其数据类型是number
-->
<el-option :value="1" label="高级讲师"/>
<el-option :value="2" label="首席讲师"/>
</el-select>
</el-form-item>
<el-form-item label="讲师资历">
<el-input v-model="teacher.career"/>
</el-form-item>
<el-form-item label="讲师简介">
<el-input v-model="teacher.intro" :rows="10" type="textarea"/>
</el-form-item>
<!-- 讲师头像:TODO -->
<!-- 讲师头像 -->
<el-form-item label="讲师头像">
<!-- 头衔缩略图 -->
<pan-thumb :image="teacher.avatar"/>
<!-- 文件上传按钮 -->
<el-button type="primary" icon="el-icon-upload" @click="imagecropperShow=true">更换头像
</el-button>
<!--
v-show:是否显示上传组件
:key:类似于id,如果一个页面多个图片上传控件,可以做区分
:url:后台上传的url地址
@close:关闭上传组件
@crop-upload-success:上传成功后的回调 -->
<image-cropper
v-show="imagecropperShow"
:width="300"
:height="300"
:key="imagecropperKey"
:url="BASE_API+'/eduoss/upload/'"
field="file"
@close="close"
@crop-upload-success="cropSuccess"/>
</el-form-item>
<el-form-item>
<el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate">保存</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import teacherApi from '@/api/teacher/teacher'
//引入组件
import ImageCropper from '@/components/ImageCropper'
import PanThumb from '@/components/PanThumb'
export default {
components:{ImageCropper,PanThumb},//声明组件
data() {
return {
teacher: {
name: '',
sort: 0,
level: 1,
career: '',
intro: '',
avatar: ''
},
// 保存按钮是否禁用,
saveBtnDisabled: false,
BASE_API: process.env.BASE_API, // 接口API地址
imagecropperShow: false, // 是否显示上传组件
imagecropperKey: 0 // 上传组件id
}
},
created(){//页面渲染前执行
this.init()
},
watch: {
$$route(to,from){//路由变化方式 路由发生变化 方法就会执行
// this.init()
this.teacher = {...defaultForm}
}
},
methods: {
close(){//上传关闭弹框的方法
this.imagecropperShow=false;
this.imagecropperKey = this.imagecropperKey+1
},
cropSuccess(data){//上传成功的方法
this.imagecropperShow=false;
//上传完后返回图片地址
this.teacher.avatar = data.url
this.imagecropperKey = this.imagecropperKey+1
},
init(){
if (this.$route.params && this.$route.params.id) {//判断路径是否有id值
const id = this.$route.params.id //从路径中获取id值
this.getInfo(id) //调用根据id查询的方法
}else{//路径中没有id值
//清空表单
this.teacher = {...defaultForm}
}
},
getInfo(id){//根据讲师id查询的方法
teacherApi. getTeacherInfo(id)
.then(response=>{
this.teacher = response.data.eduTeacher
})
},
saveOrUpdate() {
//根据teacher是都有id 判断修改还是添加
if(!this.teacher.id){
//添加
this.saveBtnDisabled = true
this.saveTeacher()
}else{
// 修改
this.updateTeacher()
}
},
updateTeacher(){
teacherApi.updateTeacher(this.teacher)
.then(response =>{//修改成功
this.$message({
type: 'success',
message: '修改成功!'
});
this.$router.push({path:'/teacher/table'})
})
},
// 保存 添加讲师的方法
saveTeacher() {
teacherApi.save(this.teacher)
.then(response =>{//保存成功
this.$message({
type: 'success',
message: '添加成功!'
});
this.$router.push({path:'/teacher/table'})
})
}
}
}
</script>
启动java项目和前端项目 输入npm run dev