阿里云OSS介绍、后端集成与代码全流程演示

1.阿里云对象存储OSS

为了解决海量数据存储弹性扩容,项目中我们采用云存储的解决方案- 阿里云OSS。 

1.1 开通“对象存储OSS”服务

(1)申请阿里云账号

(2)实名认证

(3)开通“对象存储OSS”服务

(4)进入管理控制台

1.1.1 创建Bucket

选择:标准存储、公共读、不开通

1.1.2 上传默认头像

创建文件夹avatar,上传默认的用户头像

1.1.3 创建RAM子用户

(1)添加用户组

(2)添加用户

(3)添加用户到用户组

(4)设置用户组权限:AliyunOSSFullAccess

(5)获取子用户AccessKeyId,AccessKeySecret

1.2 使用SDK

1.2.1 创建Mavaen项目

com.atguigu

aliyun-oss

1.2.2 pom

<dependencies>

    <!--aliyunOSS-->

    <dependency>

        <groupId>com.aliyun.oss</groupId>

        <artifactId>aliyun-sdk-oss</artifactId>

        <version>2.8.3</version>

    </dependency>

​

    <dependency>

        <groupId>junit</groupId>

        <artifactId>junit</artifactId>

        <version>4.12</version>

    </dependency>

</dependencies>

1.2.3 找到编码时需要用到的常量值

(1)endpoint

(2)bucketName

(3)accessKeyId

(4)accessKeySecret

1.2.4 测试创建Bucket的连接


public class OSSTest {

    @Test
    public void oss(){
        // Endpoint以杭州为例,其它Region请按实际情况填写。
        String endpoint = "http://oss-cn-beijing.aliyuncs.com";
        // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
        String accessKeyId = "<yourAccessKeyId>";
        String accessKeySecret = "<yourAccessKeySecret>";

        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

        // 创建存储空间。
        String bucketName = "sgg-hw";
        // 新建存储空间默认为标准存储类型,私有权限。
        ossClient.createBucket(bucketName);

        // 关闭OSSClient。
        ossClient.shutdown();
    }

}

2. 存储服务-测试

2.1 创建模块

Artifact:test_oss

2.3 配置pom.xml

<dependencies>
    <dependency>
        <groupId>com.test</groupId>
        <artifactId>test_common</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <!--aliyunOSS-->
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
        <version>2.8.3</version>
    </dependency>
    <!--日期时间工具-->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>2.10.1</version>
    </dependency>
</dependencies>

2.4 配置application.properties

#服务端口
server.port=8002
#服务名
spring.application.name=test-oss
#环境设置:dev、test、prod
spring.profiles.active=dev

#阿里云 OSS
#不同的服务器,地址不同
aliyun.oss.file.endpoint=your endpoint
aliyun.oss.file.keyid=your accessKeyId
aliyun.oss.file.keysecret=your accessKeySecret
#bucket可以在控制台创建,也可以使用java代码创建
aliyun.oss.file.bucketname=test-file
aliyun.oss.file.filehost=avatar

2.5 logback-spring.xml

修改日志路径

2.6 创建启动类

创建OssApplication.java

2.7 启动项目

报错

springboot会默认加载

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration这个类,

而DataSourceAutoConfiguration类使用了@Configuration注解向spring注入了dataSource bean,又因为项目(oss模块)中并没有关于dataSource相关的配置信息,所以当spring创建dataSource bean时因缺少相关的信息就会报错。

解决办法:

方法1、在@SpringBootApplication注解上加上exclude,解除自动加载DataSourceAutoConfiguration

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

方法2、common项目中mybatis-plus-boot-starter配置添加<optional>true</optional>

此种方式会引起后续的包扫描问题,后面再详解,此处先使用第一种方式

3. 后端实现文件上传

3.1 从配置文件读取常量

创建常量读取工具类:ConstantPropertiesUtil.java

使用@Value读取application.properties里的配置内容

用spring的 InitializingBean 的 afterPropertiesSet 来初始化配置信息,这个方法将在所有的属性被初始化后调用。

package com.test.oss.utils;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@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.filehost}")
    private String fileHost;

    @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;
    public static String FILE_HOST ;

    @Override
    public void afterPropertiesSet() throws Exception {
        END_POINT = endpoint;
        ACCESS_KEY_ID = keyId;
        ACCESS_KEY_SECRET = keySecret;
        BUCKET_NAME = bucketName;
        FILE_HOST = fileHost;
    }
}

3.2 文件上传

创建Service接口:FileService.java

package com.test.oss.service;

import org.springframework.web.multipart.MultipartFile;

public interface FileService {
    /**
     * 文件上传至阿里云
     * @param file
     * @return
     */
    String upload(MultipartFile file);
}

实现:FileServiceImpl.java

参考SDK中的:Java->上传文件->简单上传->流式上传->上传文件流

package com.test.oss.service;

import com.aliyun.oss.OSSClient;
import com.test.oss.util.ConstantPropertiesUtil;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.UUID;

@Service
public class FileServiceImpl implements FileService{

    private static String TYPESTR[] = {".png",".jpg",".bmp",".gif",".jpeg"};

    @Override
    public String upload(MultipartFile file) {
        OSSClient ossClient = null;
        String url = null;
        try {
            // 创建OSSClient实例。
            ossClient = new OSSClient(
                    ConstantPropertiesUtil.END_POINT,
                    ConstantPropertiesUtil.ACCESS_KEY_ID,
                    ConstantPropertiesUtil.ACCESS_KEY_SECRET);
            boolean flag = false;
            //判断文件格式
            for(String type : TYPESTR){
                if(StringUtils.endsWithIgnoreCase(file.getOriginalFilename(),type)){
                    flag = true;
                    break;
                }
            }
            if(!flag){
                return "图片格式不正确";
            }
            //判断文件内容
            BufferedImage image = ImageIO.read(file.getInputStream());
            if(image != null){
                System.err.println(String.valueOf(image.getHeight()));
                System.err.println(String.valueOf(image.getWidth()));
            } else{
                return "文件内容不正确";
            }
            //获取文件名称
            String filename = file.getOriginalFilename();
            //文件名字: lijin.shuai.jpg
            String ext = filename.substring(filename.lastIndexOf("."));
            String newName = UUID.randomUUID().toString() + ext;// ertyerxvnxrvjtcfhjktcfgh
            String dataPath = new DateTime().toString("yyyy/MM/dd");
            String urlPath = ConstantPropertiesUtil.FILE_HOST + "/" + dataPath + "/" + newName;
            // 上传文件流。
            InputStream inputStream = file.getInputStream();
            ossClient.putObject(ConstantPropertiesUtil.BUCKET_NAME, urlPath, inputStream);
            url = "https://"+ConstantPropertiesUtil.BUCKET_NAME + "." + ConstantPropertiesUtil.END_POINT + "/" + urlPath;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }

        return url;

    }
}

可以添加枚举

FILE_UPLOAD_ERROR(false, 21004, "文件上传错误");

在抛异常的时候使用:

throw new EduException(ResultCode.FILE_UPLOAD_ERROR);

3.3 控制层

创建controller:FileUploadController.java

package com.test.oss.controller;

import com.test.oss.service.FileService;
import com.test.common.entity.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

@Api(description="阿里云文件管理")
@CrossOrigin //跨域
@RestController
@RequestMapping("/oss/file")
public class FileController {

    @Autowired
    private FileService fileService;

    /**
     * 文件上传
     *
     * @param file
     */
    @ApiOperation(value = "文件上传")
    @PostMapping("upload")
    public Result upload(
            @ApiParam(name = "file", value = "文件", required = true)
            @RequestParam("file") MultipartFile file) {

        String uploadUrl = fileService.upload(file);
        //返回r对象
        return Result.ok().message("文件上传成功").data("url", uploadUrl);
    }
}

3.4 重启oss服务

3.5 配置Swagger

package com.test.oss.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class Swagger2Config {

    @Bean
    public Docket webApiConfig(){

        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                .build();

    }

    private ApiInfo webApiInfo(){

        return new ApiInfoBuilder()
                .title("网站-文档")
                .description("本文档描述了接口定义")
                .version("1.0")
                .contact(new Contact("华安", "http://xxx.com", "492902688@qq.com"))
                .build();
    }

}

3.6 Swagger中测试文件上传

3.7 配置nginx反向代理

将接口地址加入nginx配置

location ~ /oss/ {           

    proxy_pass http://localhost:8002;

}

重启nginx

nginx -s reload

4. 前端整合图片上传组件

需要上传图片的插件!

4.1 复制头像上传组件

从vue-element-admin复制组件:

vue-element-admin/src/components/ImageCropper

vue-element-admin/src/components/PanThumb

4.2 前端添加文件上传组件

src/views/edu/teacher/add.vue

template:

<!-- 讲师头像: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+'/oss/file/upload'"

                        field="file"

                        @close="close"

                        @crop-upload-success="cropSuccess"/>

      </el-form-item> 

引入组件模块

import ImageCropper from '@/components/ImageCropper'

import PanThumb from '@/components/PanThumb'

4.3 设置默认头像

config/dev.env.js中添加阿里云oss bucket地址

OSS_PATH: '"http://guli-test.oss-cn-beijing.aliyuncs.com"'

组件中初始化头像默认地址

const defaultForm = {

  ......,

  avatar: process.env.OSS_PATH + '/avatar/default.jpg'

}

4.4 js脚本实现上传和图片回显

export default {

  components: { ImageCropper, PanThumb },

  data() {

    return {

      //其它数据模型

      ......,

        

      BASE_API: process.env.BASE_API, // 接口API地址

      imagecropperShow: false, // 是否显示上传组件

      imagecropperKey: 0 // 上传组件id

    }

  },

    

  ......,

    

  methods: {

    //其他函数

    ......,

    // 上传成功后的回调函数

    cropSuccess(data) {

      console.log(data)

      this.imagecropperShow = false

      this.teacher.avatar = data.url

      // 上传成功后,重新打开上传组件时初始化组件,否则显示上一次的上传结果

      this.imagecropperKey = this.imagecropperKey + 1

    },

    // 关闭上传组件

    close() {

      this.imagecropperShow = false

      // 上传失败后,重新打开上传组件时初始化组件,否则显示上一次的上传结果

      this.imagecropperKey = this.imagecropperKey + 1

    }

  }

}

4.5 测试文件上传

前后端联调

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵然间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值