阿里 对象存储OSS 云存储服务

news2024/11/20 9:33:32

1.简介

对象存储服务(Object Storage Service ,OSS) 是一种 海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。

2.如何使用。参考文档

 

看文档,说的很明白,这里就不演示了

3. SpringCloudAlibaba-OSS

spring-cloud-alibaba/README-zh.md at 2022.x · alibaba/spring-cloud-alibaba · GitHub

好像新版本没有starter了

自己封装一下原生API吧

package com.jmj.gulimall.product.config;

import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OssClientConfiguration {

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

    @Bean
    public OSS ossClient() {
        // 创建OSSClient实例。
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKey, secretKey);
        // 创建ClientBuilderConfiguration。
        // ClientBuilderConfiguration是OSSClient的配置类,可配置代理、连接超时、最大连接数等参数。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        // 设置Socket层传输数据的超时时间,默认为50000毫秒。
        conf.setSocketTimeout(10000);
        // 设置建立连接的超时时间,默认为50000毫秒。
        conf.setConnectionTimeout(10000);
        // 设置失败请求重试次数,默认为3次。
        conf.setMaxErrorRetry(5);
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider,conf);
        return ossClient;
    }


}
package com.jmj.gulimall.product.ossclient;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

@Component
@Slf4j
public class OssClientTemplate {

    @Autowired
    private OSS ossClient;

    public Boolean uploadFile(String bucketName, String objectName, File file) {
        // 创建PutObjectRequest对象。
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, file);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }
        return false;
    }

    public Boolean uploadFile(String bucketName, String objectName, String content){
        // 创建PutObjectRequest对象。
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(content.getBytes());
        try {

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, byteArrayInputStream);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }finally {
            if (byteArrayInputStream!=null){
                try {
                    byteArrayInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    public Boolean uploadFile(String bucketName, String objectName, InputStream inputStream){
        // 创建PutObjectRequest对象。
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }finally {
            if (inputStream!=null){
                try {
                    //其实流已经被关闭了,我再关闭一下保险一点
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }
    public Boolean uploadFile(String objectName, InputStream inputStream){
        // 创建PutObjectRequest对象。
        return uploadFile("gulimall-jmj", objectName, inputStream);
    }
}

4.后端签名直传

package com.jmj.gulimall.third.config;

import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.jmj.gulimall.third.ossclient.OssClientTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties({OssConfigurationProperties.class})
@Slf4j
@RefreshScope //动态从配置中心获取配置
public class OssClientConfiguration {

    @Autowired
    private OssConfigurationProperties ossConfigurationProperties;

    @Bean
    public OSS ossClient() {
        // 创建OSSClient实例。
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(ossConfigurationProperties.getAccessKey(), ossConfigurationProperties.getSecretKey());
        // 创建ClientBuilderConfiguration。
        // ClientBuilderConfiguration是OSSClient的配置类,可配置代理、连接超时、最大连接数等参数。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        // 设置是否支持CNAME。CNAME用于将自定义域名绑定到目标Bucket。
        conf.setSupportCname(true);
        // 设置Socket层传输数据的超时时间,默认为50000毫秒。
        conf.setSocketTimeout(10000);
        // 设置建立连接的超时时间,默认为50000毫秒。
        conf.setConnectionTimeout(10000);
        // 设置失败请求重试次数,默认为3次。
        conf.setMaxErrorRetry(5);
        OSS ossClient = new OSSClientBuilder().build(ossConfigurationProperties.getEndpoint(), credentialsProvider, conf);
        log.info("ossClient初始化完成,properties={}",ossConfigurationProperties);
        return ossClient;
    }


    @Bean
    public OssClientTemplate ossClientTemplate(OSS ossClient) {
        return new OssClientTemplate(ossClient,ossConfigurationProperties);
    }

}
package com.jmj.gulimall.third.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;

@ConfigurationProperties(prefix = "spring.cloud.alicloud")
@Data
@RefreshScope //动态从配置中心获取配置
public class OssConfigurationProperties {

    private String accessKey;

    private String secretKey;

    private String endpoint;

    private String regionEnd;

    private String bucket;



}
package com.jmj.gulimall.third.controller;

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.jmj.gulimall.third.common.R;
import com.jmj.gulimall.third.config.OssConfigurationProperties;
import com.jmj.gulimall.third.ossclient.OssClientTemplate;
import lombok.extern.slf4j.Slf4j;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@RestController
@Slf4j
@RequestMapping("/oss")
public class OssController {

    @Autowired
    private OssClientTemplate ossClientTemplate;

    @Autowired
    private OssConfigurationProperties properties;

    @GetMapping("/policy")
    public R policy(HttpServletRequest request, HttpServletResponse response) {

        // 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。
//                String callbackUrl = "https://192.168.0.0:8888";
        // 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。

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

        OSS ossClient = ossClientTemplate.getOssClient();
        String accessKeyId = properties.getAccessKey();
        String regionEnd = properties.getRegionEnd();
        String bucket = properties.getBucket();
        String host = "https://" + bucket + "." + regionEnd;
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            // PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
            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 accessId = accessKeyId;
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            Map<String, String> 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));
            return R.ok().put("data",respMap);

        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            log.error(e.getMessage(), e);
        }
        return  R.error("上传签名异常");
    }


}
package com.jmj.gulimall.third.ossclient;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.jmj.gulimall.third.config.OssConfigurationProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

@Slf4j
public class OssClientTemplate {

    private OSS ossClient;

    public OSS getOssClient() {
        return ossClient;
    }
    private OssConfigurationProperties properties;

    public OssClientTemplate(OSS ossClient, OssConfigurationProperties properties) {
        this.ossClient = ossClient;
        this.properties = properties;
    }

    public Boolean uploadFile(String bucketName, String objectName, File file) {
        // 创建PutObjectRequest对象。
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, file);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }
        return false;
    }

    public Boolean uploadFile(String bucketName, String objectName, String content){
        // 创建PutObjectRequest对象。
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(content.getBytes());
        try {

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, byteArrayInputStream);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }finally {
            if (byteArrayInputStream!=null){
                try {
                    byteArrayInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    public Boolean uploadFile(String bucketName, String objectName, InputStream inputStream){
        // 创建PutObjectRequest对象。
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }finally {
            if (inputStream!=null){
                try {
                    //其实流已经被关闭了,我再关闭一下保险一点
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }
    public Boolean uploadFile(String objectName, InputStream inputStream){
        // 创建PutObjectRequest对象。
        return uploadFile(properties.getBucket(), objectName, inputStream);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1570320.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeNet卷积神经网络

文章目录 简介conv2d网络层的结构 简介 它是最早发布的卷积神经网络之一 conv2d 这个卷积成的参数先进行介绍一下&#xff1a; self.conv1 nn.Conv2d(in_channels3, out_channels10, kernel_size3, stride1, padding1)先看一下in_channels 输入的通道数&#xff0c;out_cha…

Kotlin学习日志(一)TextView、Button、Toast的使用(1)

android:layout_width“wrap_content” android:layout_height“wrap_content”/> import kotlinx.android.synthetic.main.activity_main.* 这句话的意思是引进Kotlin的的控件变量自动映射功能&#xff0c;接下来只要是这个activity_main.xml文件中的控件&#xff0c;我…

Xshell Plus 详细安装教程以及附带使用图文教程

一、下载 Xshell Plus 6 完成后&#xff0c;请按照下面教程操作 1、下载 Xshell Plus 6 完成后&#xff0c;并解压 zip 包: 2、进入解压后的文件夹后&#xff0c;如果你之前安装了 Xshell&#xff0c; 先点击 !卸载.bat 卸载 xshell&#xff0c; 然后再点击 !绿化.bat; 如果是…

Pygame基础10-物理模拟

PyMunk PyMunk是一个模拟物理的库。 注意&#xff0c;PyMunk只是进行物理模拟&#xff0c;不包含可视化的功能。如果需要可视化&#xff0c;可使用pygame等库。 可用pip安装pymunk pip install pymunk pymunk中的概念&#xff1a; space&#xff1a; 物理空间。 包含gravity 模…

[问题记录] oracle问题汇总记录

plsql问题 1、oracle-initialization error could not locate OCI.dll 下载plsql客户端后&#xff0c;登录显示如图所示的错误 解决方法&#xff0c;点击下方链接&#xff0c;下载64位客户端 Instant Client for Microsoft Windows (x64) 64-bit (oracle.com) 2、显示中文乱…

如何打包一个手机软件

目录 前言&#xff1a; 准备工具&#xff1a; 创建项目&#xff1a; 打包程序&#xff1a; 前言&#xff1a; 我们平时手机上使用的程序&#xff0c;或者电脑上使用的程序都可以由Web程序打包而来的&#xff0c;而打包不是一个.html文件也不是一个.js文件而是一个大型的文…

可视化大屏的行业应用(3):智慧旅游智慧景区

可视化大屏在智慧旅游和智慧景区中具有重要的应用价值&#xff0c;可以帮助景区管理者更好地了解景区的情况&#xff0c;提高游客的满意度和体验&#xff0c;促进景区的发展。 实时监控&#xff1a; 可视化大屏可以将景区内的各种数据实时监控&#xff0c;包括游客数量、交通…

VC++建立空文档失败的一种情形

假设现在要在单文档程序的客户区创建控件; 把控件作为视类的成员变量; 先把成员变量定义加到视类头文件; 然后在视类的, BOOL CMyttView::PreCreateWindow(CREATESTRUCT& cs) {....... } 在此成员函数中创建控件; 运行程序,就会出现如下错误, 这就需要在类向导…

企业员工岗前培训管理系统的设计与实现(论文+源码)_kaic

摘 要 有效的处理想要的相关信息和如何传播有效的信息&#xff0c;一直是人类不断探索的动力。人类文明火种的传承都是通过了多种媒介作为载体&#xff0c;也是随着社会生产力的发展不断的更新。随着互联网的到来&#xff0c;信息传播与管理都上升了一个新的台阶&#xff0c;并…

Linux课程____LVM(逻辑卷管理器)

LVM 技术是在硬盘分区和文件系统之间添加了一个逻辑层&#xff0c;它提供了一个抽象的卷组&#xff0c;可以把多块硬盘进行卷组合并。 这样一来&#xff0c;用户不必关心物理硬盘设备的底层架构和布局&#xff0c;就可以实现对硬盘分区的动态调整。 动态调整磁盘容量&#xff…

蓝桥杯备考3

P8196 [传智杯 #4 决赛] 三元组 题目描述 给定一个长度为 n 的数列 a&#xff0c;对于一个有序整数三元组 (i,j,k)&#xff0c;若其满足 1≤i≤j≤k≤n 并且&#xff0c;则我们称这个三元组是「传智的」。 现在请你计算&#xff0c;有多少有序整数三元组是传智的。 输入格式…

Rust---复合数据类型之结构体

目录 结构体的使用输出结果 结构体简化创建结构体更新语法元组结构体单元结构体&#xff08;unit struct&#xff09;结构体中的引用使用#[derive(Debug)]再次介绍 代码综合展示 与元组不同的是&#xff0c;结构体可以为内部的每个字段起一个富有含义的名称&#xff0c;因此无需…

Qt+OpenGL_part1

OpenGL&#xff0c;Qt实现&#xff1a;1入门篇(已更完)_哔哩哔哩_bilibili OpenGL3.3以上是现代模式&#xff08;可编程管线&#xff09;&#xff1a; 状态机 状态设置函数&#xff08;State-changing Function) 状态应用函数 &#xff08;State-using Function) OpenGL的状态…

VB 通过COM接口解析PSD文件

最近有PS测评的需求&#xff0c;故而想到了解析psd文件&#xff0c;目的就是为了获取文档信息和图层信息&#xff1b;获取PS的图像信息有很多方式&#xff0c;有过程性的&#xff0c;比如监听PS的各种操作事件&#xff1b;有结果性的&#xff0c;比如本文写的解析PSD文件。 0.…

易语言创建数据库

易语言是一门中文编程语言&#xff0c;由国人开发&#xff0c;虽然比较冷门&#xff0c;但是在有些场合却非常流行&#xff0c;比如自动化脚本&#xff0c;还有开发外挂。 以下将用一个简单的用户表&#xff0c;演示易语言创建数据库的几种方式&#xff1a; 1. 使用菜单创建数…

无人售货奶柜:开启便捷生活的新篇章

无人售货奶柜&#xff1a;开启便捷生活的新篇章 在这个快节奏的现代生活中&#xff0c;科技的革新不仅为我们带来了前所未有的便利&#xff0c;更在不经意间改变着我们的日常。其中&#xff0c;无人售货技术的出现&#xff0c;尤其是无人售货奶柜&#xff0c;已经成为我们生活…

pta 1086 就不告诉你

1086 就不告诉你 分数 15 全屏浏览 切换布局 作者 CHEN, Yue 单位 浙江大学 做作业的时候&#xff0c;邻座的小盆友问你&#xff1a;“五乘以七等于多少&#xff1f;”你应该不失礼貌地围笑着告诉他&#xff1a;“五十三。”本题就要求你&#xff0c;对任何一对给定的正整数…

图像拼接——最小割准则提取拼接缝

一、最大流问题与Ford-Fulkerson算法介绍 二、最大流与最小割 显然,我们有对任意一个割,穿过该割的净流量上界就是该割的容量,即不可能超过割的容量。所以网络的最大流必然无法超过网络的最小割。最小割是指割的容量最小,最大流是指网络当中最大的净流量,简单的例子s是水龙…

Vue3从入门到实战:路由知识点

本人在B站上关于vue3的尚硅谷的课程&#xff0c;以下是整理一些笔记。 1.两个知识点 1.路由组件通常存放在pages 或 views文件夹&#xff0c;一般组件通常存放在components文件夹。 组件可以分为&#xff1a; 1. 一般组件&#xff1a;亲手写标签出来的 2. 路由组件&#…

武汉星起航电子商务公司领航跨境电商新纪元,助力品牌走向全球

在全球经济一体化的时代背景下&#xff0c;跨境电商正成为推动国际贸易增长的重要力量。武汉星起航电子商务有限公司&#xff0c;作为一家专注于提供一站式解决方案的跨境电商服务商&#xff0c;凭借其丰富的实战经验和专业团队&#xff0c;在行业中取得了令人瞩目的成绩。 自…