SpringCloud integra Alibaba Cloud OSS para implementar la carga de archivos

Sitio web oficial de Alibaba Cloud OSS: Consola de administración de OSS (aliyun.com)

¿Qué es el almacenamiento de objetos OSS?

Alibaba Cloud Object Storage OSS (Object Storage Service) es un servicio de almacenamiento en la nube masivo, seguro, de bajo costo y altamente confiable que puede proporcionar una durabilidad de datos del 99,9999999999% (12 nueves) y una disponibilidad de datos del 99,995%. Hay una variedad de tipos de almacenamiento disponibles para optimizar completamente los costos de almacenamiento.

OSS tiene una interfaz API RESTful independiente de la plataforma. Puede almacenar y acceder a cualquier tipo de datos en cualquier aplicación, en cualquier momento y en cualquier lugar.

Puede utilizar la API, la interfaz SDK o la herramienta de migración OSS proporcionada por Alibaba Cloud para mover fácilmente datos masivos dentro o fuera de Alibaba Cloud OSS. Una vez que los datos se almacenan en Alibaba Cloud OSS, puede elegir el almacenamiento estándar (Estándar) como el método de almacenamiento principal para aplicaciones móviles, sitios web grandes, intercambio de imágenes o audio y video calientes, o puede elegir almacenamiento de acceso de baja frecuencia con un costo menor. y un período de almacenamiento más largo (Acceso poco frecuente), almacenamiento de archivos (Archivo) y almacenamiento de archivos en frío (Cold Archive) se utilizan como métodos de almacenamiento para datos a los que se accede con poca frecuencia.

1. Abre una cuenta y crea un espacio.

  1. Crear una cuenta en la nube de Alibaba
  2. Activar el servicio OSS de almacenamiento de objetos
  3. Ingrese a la consola OSS y cree una nueva consola de administración OSS (aliyun.com)

         El nombre del depósito se puede completar a voluntad y se puede seleccionar la región más cercana a nuestra región actual. Debido a que es una prueba, nuestro tipo de almacenamiento selecciona acceso de baja frecuencia y, para los permisos de lectura y escritura, seleccionamos Lectura de anuncio.

        4. Una vez completada la creación, haga clic en la esquina superior derecha para ingresar AccessKey y seleccione comenzar a usar la clave de subcuenta.

 

        5. Después de crear la subcuenta, conserve la cuenta y la clave generadas. Usaremos esta subcuenta para operaciones en el futuro. 

        6. Nuestro punto final y otra información se pueden ver en la descripción general de la consola.

2. Simplemente use el cliente OSS en Java para cargar archivos al servidor.

  1. Importar dependencia spring-cloud-starter-alicloud-oss
      <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>

2. Agregar configuración (clave de acceso, clave secreta, endoint)

spring:
  cloud:
    alicloud:
      access-key: 你的 access-key
      secret-key: 你的 secret-key
      oss:
        endpoint: oss-cn-shenzhen.aliyuncs.com

        Nota: el punto final está bajo el paquete oss

3. Escriba una clase de prueba para probar la carga de imágenes al servidor OSS.


    @Resource
    OSS ossClient;

    @Test
    public void uploadDemo() throws FileNotFoundException {
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "hola76";
        // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
        String objectName = "1111727083.jpg";
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
        String filePath= "C:\\Users\\Administrator\\Pictures\\111727083.jpg";

        // 创建OSSClient实例。
        //OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        InputStream inputStream = new FileInputStream(filePath);
        // 创建PutObject请求。
        ossClient.putObject(bucketName, objectName, inputStream);
        System.out.println("上传成功!");
        ossClient.shutdown();

    }

4. Vaya a la consola para ver

5. Imagen cargada exitosamente 

3. Transmisión directa de firma del lado del servidor y configuración de devolución de llamada de carga

Documento oficial: firma del lado del servidor y transmisión directa (aliyun.com)

1.Introducción al proceso

El proceso se muestra en la siguiente figura:

Cuando un usuario desea cargar un archivo en OSS y desea devolver el resultado de la carga al servidor de aplicaciones, debe configurar una función de devolución de llamada para notificar al servidor de aplicaciones de la solicitud. Una vez que el usuario carga el archivo, no obtendrá el resultado directamente, sino que primero notificará al servidor de la aplicación y luego transmitirá el resultado al usuario. 

2.Implementación de JAVA

1. Crearemos un nuevo proyecto específicamente para brindarnos servicios de terceros. La estructura del proyecto es la siguiente

2. Introduzca las dependencias de Alibaba Cloud OSS y las dependencias de openFeign (el registro y el descubrimiento de servicios se incluyen en común)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.liucan.gulimall</groupId>
    <artifactId>gulimall-third-party</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall-third-party</name>
    <description>第三方服务</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.liucan.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <groupId>com.baomidou</groupId>
                    <artifactId>mybatis-plus-boot-starter</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.vaadin.external.google</groupId>
                    <artifactId>android-json</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.8.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.liucan.gulimall.thirdparty.GulimallThirdPartyApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

3. Agregue @EnableDiscoveryClient a la clase de inicio para habilitar el registro y el descubrimiento del servicio, y configure la dirección del centro de registro en application.yml

spring:
  application:
    name: gulimall-third-party
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
server:
  port: 30000
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class GulimallThirdPartyApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallThirdPartyApplication.class, args);
    }

}

4. Ingrese nacos y cree un nuevo espacio de nombres para el servicio actual  con el ID de datos del tercero.

5. En nacos [Gestión de configuración] - [Lista de configuración], cambie al espacio de nombres de terceros que acabamos de crear y  cree una nueva configuración.

 La configuración es la siguiente:

6. Cree un nuevo bootstrap.properties en el recurso  del proyecto para especificar la dirección de nuestro centro de configuración y el espacio de nombres que se leerá.

spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=be8c72c0-916d-4bd8-8f80-14916ade1faf

spring.cloud.nacos.config.extension-configs[0].data-id=oss.yml
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[0].refresh=true

7. Cree una nueva prueba OSSContrller para obtener la firma de la Política.

package com.liucan.gulimall.thirdparty.controller;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

@RestController
public class OSSCntroller {

    @Autowired
    OSS ossClient;

    @Value("${spring.cloud.alicloud.oss.endpoint}")
    private String endpoint;
    @Value("${spring.cloud.alicloud.access-key}")
    private String accessId;
    @Value("${spring.cloud.alicloud.secret-key}")
    private String accessKey;
    @Value("${spring.cloud.alicloud.oss.bucket}")
    private String bucket;

    @RequestMapping("/oss/policy")
    public Map<String, String> policy(){
        // 填写Host地址,格式为https://bucketname.endpoint。
        String host = "https://"+bucket+"."+endpoint;
        // 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。
        String callbackUrl = "https://192.168.0.0:8888";
        // 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。

        String dateDir = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dir = dateDir+"/";

        // 创建ossClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);

        Map<String, String> respMap = null;
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            respMap = new LinkedHashMap<String, 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));
            // respMap.put("expire", formatISO8601Date(expiration));

            JSONObject jasonCallback = new JSONObject();
            jasonCallback.put("callbackUrl", callbackUrl);
            jasonCallback.put("callbackBody",
                    "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
            jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
            String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
            respMap.put("callback", base64CallbackBody);
        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        }
        return respMap;
    }
}

8. Solicitar localhost:30000/oss/policy

 Después de obtener con éxito la firma, el usuario primero solicita esta interfaz antes de cargar la imagen y luego solicita directamente a Alibaba Cloud con la firma devuelta por esta interfaz. Luego se puede cargar directamente en Alibaba Cloud OSS. No es necesario que el flujo de archivos sea Se guarda en nuestro servidor y luego se reenvía. Esta es la transmisión directa de la firma del lado del servidor.

9. Entregue el servicio a Gateway para una gestión de enrutamiento unificada.

        1. Agregar configuración de enrutamiento en el módulo Gateway

        Nuestra entrada unificada para acceder a los servicios OSS es api/thirdparty/

spring:
  cloud:
    gateway:
      routes:
       - id: product_route
         uri: lb://gulimall-product #lb開啓負載均衡 路由到服務名為gulimall_product的服务
         predicates:
          - Path=/api/product/**
         filters:
          - RewritePath=/api/product/(?<segment>/?.*),/product/$\{segment}

       - id: third_party_route
         uri: lb://gulimall-third-party #lb開啓負載均衡 路由到服務名為gulimall-third-party的服务
         predicates:
          - Path=/api/thirdparty/**
         filters:
          - RewritePath=/api/thirdparty/(?<segment>/?.*),/$\{segment}

       - id: admin_route
         uri: lb://renren-fast #lb開啓負載均衡 路由到服務名為renren-fast的服务
         predicates:
         - Path=/api/**
         filters:
         - RewritePath=/api/(?<segment>/?.*),/renren-fast/$\{segment}

        2. Reinicie Gateway y visite

 4. Carga de prueba de depuración conjunta de front-end y back-end de OOS

1. Agregue una nueva carpeta de carga en src/components para almacenar los componentes cargados:

política.js:

import http from '@/utils/httpRequest.js'
export function policy() {
   return  new Promise((resolve,reject)=>{
        http({
            url: http.adornUrl("/thirdparty/oss/policy"),
            method: "get",
            params: http.adornParams({})
        }).then(({ data }) => {
            resolve(data);
        })
    });
}

singleUpload.vue: (cambie la ruta de carga al nombre de dominio público de nuestro Bucket, que se puede ver en la consola OSS)

<template> 
  <div>
    <el-upload action="http://hola76.oss-cn-shenzhen.aliyuncs.com" :data="dataObj" list-type="picture" :multiple="false" :show-file-list="showFileList" :file-list="fileList" :before-upload="beforeUpload" :on-remove="handleRemove" :on-success="handleUploadSuccess" :on-preview="handlePreview">
      <el-button size="small" type="primary">点击上传</el-button>
      <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过10MB</div>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
      <img width="100%" :src="fileList[0].url" alt="">
    </el-dialog>
  </div>
</template>
<script>
import { policy } from './policy'
import { getUUID } from '@/utils'

export default {
  name: 'singleUpload',
  props: {
    value: String
  },
  computed: {
    imageUrl() {
      return this.value
    },
    imageName() {
      if (this.value != null && this.value !== '') {
        return this.value.substr(this.value.lastIndexOf('/') + 1)
      } else {
        return null
      }
    },
    fileList() {
      return [
        {
          name: this.imageName,
          url: this.imageUrl
        }
      ]
    },
    showFileList: {
      get: function () {
        return this.value !== null && this.value !== '' && this.value !== undefined
      },
      set: function (newValue) {}
    }
  },
  data() {
    return {
      dataObj: {
        policy: '',
        signature: '',
        key: '',
        ossaccessKeyId: '',
        dir: '',
        host: ''
        // callback:'',
      },
      dialogVisible: false
    }
  },
  methods: {
    emitInput(val) {
      this.$emit('input', val)
    },
    handleRemove(file, fileList) {
      this.emitInput('')
    },
    handlePreview(file) {
      this.dialogVisible = true
    },
    beforeUpload(file) {
      let _self = this
      return new Promise((resolve, reject) => {
        policy()
          .then(response => {
            _self.dataObj.policy = response.data.policy
            _self.dataObj.signature = response.data.signature
            _self.dataObj.ossaccessKeyId = response.data.accessid
            _self.dataObj.key = response.data.dir + '/' + getUUID() + '_${filename}'
            _self.dataObj.dir = response.data.dir
            _self.dataObj.host = response.data.host
            resolve(true)
          })
          .catch(err => {
            reject(false)
          })
      })
    },
    handleUploadSuccess(res, file) {
      console.log('上传成功...')
      this.showFileList = true
      this.fileList.pop()
      this.fileList.push({ name: file.name, url: this.dataObj.host + '/' + this.dataObj.key.replace('${filename}', file.name) })
      this.emitInput(this.fileList[0].url)
    }
  }
}
</script>
<style>
</style>


multiUpload.vue: (La ruta de carga debe cambiarse al nombre de dominio público de nuestro Bucket, que se puede ver en la consola OSS)

<template>
  <div>
    <el-upload action="http://hola76.oss-cn-shenzhen.aliyuncs.com" :data="dataObj" list-type="picture-card" :file-list="fileList" :before-upload="beforeUpload" :on-remove="handleRemove" :on-success="handleUploadSuccess" :on-preview="handlePreview" :limit="maxCount" :on-exceed="handleExceed">
      <i class="el-icon-plus"></i>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
      <img width="100%" :src="dialogImageUrl" alt />
    </el-dialog>
  </div>
</template>
<script>
import { policy } from './policy'
import { getUUID } from '@/utils'
export default {
  name: 'multiUpload',
  props: {
    //图片属性数组
    value: Array,
    //最大上传图片数量
    maxCount: {
      type: Number,
      default: 30
    }
  },
  data() {
    return {
      dataObj: {
        policy: '',
        signature: '',
        key: '',
        ossaccessKeyId: '',
        dir: '',
        host: '',
        uuid: ''
      },
      dialogVisible: false,
      dialogImageUrl: null
    }
  },
  computed: {
    fileList() {
      let fileList = []
      for (let i = 0; i < this.value.length; i++) {
        fileList.push({ url: this.value[i] })
      }

      return fileList
    }
  },
  mounted() {},
  methods: {
    emitInput(fileList) {
      let value = []
      for (let i = 0; i < fileList.length; i++) {
        value.push(fileList[i].url)
      }
      this.$emit('input', value)
    },
    handleRemove(file, fileList) {
      this.emitInput(fileList)
    },
    handlePreview(file) {
      this.dialogVisible = true
      this.dialogImageUrl = file.url
    },
    beforeUpload(file) {
      let _self = this
      return new Promise((resolve, reject) => {
        policy()
          .then(response => {
            console.log('这是什么${filename}')
            _self.dataObj.policy = response.data.policy
            _self.dataObj.signature = response.data.signature
            _self.dataObj.ossaccessKeyId = response.data.accessid
            _self.dataObj.key = response.data.dir + '/' + getUUID() + '_${filename}'
            _self.dataObj.dir = response.data.dir
            _self.dataObj.host = response.data.host
            resolve(true)
          })
          .catch(err => {
            console.log('出错了...', err)
            reject(false)
          })
      })
    },
    handleUploadSuccess(res, file) {
      this.fileList.push({
        name: file.name,
        // url: this.dataObj.host + "/" + this.dataObj.dir + "/" + file.name; 替换${filename}为真正的文件名
        url: this.dataObj.host + '/' + this.dataObj.key.replace('${filename}', file.name)
      })
      this.emitInput(this.fileList)
    },
    handleExceed(files, fileList) {
      this.$message({
        message: '最多只能上传' + this.maxCount + '张图片',
        type: 'warning',
        duration: 1000
      })
    }
  }
}
</script>
<style>
</style>


2.Introducir y utilizar componentes en brand.vue        

<single-upload></single-upload>

<script>
import singleUpload from '../../../components/upload/singleUpload.vue'
</script>

 3. Efecto

        Se descubrió que se produjo un problema entre dominios al solicitar cargar Alibaba Cloud OSS. 

4. Habilite el acceso entre dominios en la consola OSS

 

5. Prueba

 

 

 Proceso aproximado: haga clic en la interfaz para cargar la imagen -> solicite la política para obtener los datos de la firma -> envíe los datos de la firma y el flujo de archivos a Alibaba Cloud -> Alibaba Cloud para su verificación y almacenamiento

Supongo que te gusta

Origin blog.csdn.net/weixin_53922163/article/details/126735149
Recomendado
Clasificación