华润对象存储(OBS)工具类

目录

    • 一、备注
    • 二、工具类
    • 三、对象存储放在内网,如何实现外网访问


一、备注

1、ObjectBasicInfo、ObjectDetailInfo、ResultBody这三个类可自行替换或者去掉


二、工具类

package com.xxx.util;import com.amazonaws.HttpMethod;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.xxx.entity.huarun.ObjectBasicInfo;
import com.xxx.entity.huarun.ObjectDetailInfo;
import com.xxx.entity.huarun.ResultBody;
import com.hitachivantara.common.util.DatetimeFormat;
import com.hitachivantara.core.http.Protocol;
import com.hitachivantara.core.http.client.ClientConfiguration;
import com.hitachivantara.hcp.build.HCPClientBuilder;
import com.hitachivantara.hcp.build.HCPNamespaceClientBuilder;
import com.hitachivantara.hcp.common.auth.LocalCredentials;
import com.hitachivantara.hcp.standard.api.HCPNamespace;
import com.hitachivantara.hcp.standard.api.event.ListObjectHandler;
import com.hitachivantara.hcp.standard.define.NextAction;
import com.hitachivantara.hcp.standard.model.HCPObject;
import com.hitachivantara.hcp.standard.model.HCPObjectSummary;
import com.hitachivantara.hcp.standard.model.request.impl.CopyObjectRequest;
import com.hitachivantara.hcp.standard.model.request.impl.ListObjectRequest;
import com.obs.services.ObsClient;
import com.obs.services.model.HeaderResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.web.multipart.MultipartFile;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;/*** 华润对象存储(OBS)-工具类** @author hcs* @date 2023/6/20 17:03*/
@Slf4j
public class HuaRunOBSUtil {/*** 文件外链过期时间,7天*/private static long expire = 7 * 24 * 60 * 60;/*** 文件外链访问端口*/private static String port = "";private static RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);private static String bucketName;private static String ak;private static String sk;private static String endPoint;private static String targetDomainName;private static String replaceDomainName;/*** OBS操作客户端*/private static HCPNamespace obsClient = null;/*** 上传、下载文件时使用以下对象** 解决报错:Received fatal alert: protocol_version** 华润对象存储的服务器支持TLSv1.2(使用tcpdump命令抓包看到的)*/private static AmazonS3 S3APIClient;//private static AmazonS3 hs3Client;/*** OBS操作客户端Map,key=bucketName,value=客户端*/private static Map<String, HCPNamespace> obsClientMap = new HashMap<>();private static final String SEPARATOR = "/";public HuaRunOBSUtil(String bucketName, String ak, String sk, String endPoint, String port) {HuaRunOBSUtil.bucketName = bucketName;HuaRunOBSUtil.ak = ak;HuaRunOBSUtil.sk = sk;HuaRunOBSUtil.endPoint = endPoint;if (StringUtils.isNotBlank(port)) {HuaRunOBSUtil.port = ":" + port;}createObsClientInstance();S3APIClient = getInstance(endPoint, ak, sk, "S3SignerType", getHttpProtocol(endPoint));}public static String getBucketName() {return bucketName;}public static String getAk() {return ak;}public static String getSk() {return sk;}public static String getEndPoint() {return endPoint;}public static synchronized AmazonS3 getInstance(String endpoint, String ak, String sk,String signature, String protocol) {synchronized (AmazonS3.class) {if (null == S3APIClient) {S3APIClient = getHCPCSS3Client(endpoint, ak, sk, signature, protocol);}}return S3APIClient;}/*** 获取亚马逊S3客户端** @param endpoint* @param ak* @param sk* @param signature     S3SignerType - 表示V2*                      AWSS3V4SignerType - 表示V4* @param protocol* @return*/private static AmazonS3 getHCPCSS3Client(String endpoint, String ak, String sk, String signature, String protocol) {log.info("开始\t创建S3客户端");com.amazonaws.ClientConfiguration clientConfig = new com.amazonaws.ClientConfiguration();//使用HTTP或HTTPS协议if (protocol.toUpperCase().equals("HTTP")) {clientConfig.setProtocol(com.amazonaws.Protocol.HTTP);} else {clientConfig.setProtocol(com.amazonaws.Protocol.HTTPS);try {SSLContextBuilder builder = new SSLContextBuilder();builder.loadTrustMaterial(null, new TrustStrategy() {public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {return true;}});SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),/*** 仅指定TLSv1.2协议,解决报错:Received fatal alert: protocol_version** 如果加上其他版本的协议,有可能会报错:Received fatal alert: protocol_version** 例如指定为TLSv1.1,使用tcpdump命令抓包时如果发现TLSv1.2,则该次交互时失败的*/new String[]{"TLSv1.2"},// For Java 1.7 , 1.8//new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"},// For Java1.6-1.7//new String[] { "TLSv1" },new String[]{"TLS_RSA_WITH_AES_128_CBC_SHA"},NoopHostnameVerifier.INSTANCE);clientConfig.getApacheHttpClientConfig().setSslSocketFactory(sslsf);} catch (Exception e) {log.error("创建S3客户端出现异常:" + e.getMessage(), e);}}//连接池的连接数clientConfig.setMaxConnections(50);//V2签名 或 V4签名//S3SignerType - 表示V2//AWSS3V4SignerType - 表示V4clientConfig.setSignerOverride(signature);AmazonS3 client = AmazonS3ClientBuilder.standard().withClientConfiguration(clientConfig)/*** 以下配置为false:外链格式:存储桶.endpoint/目录/文件名* 以下配置为true:外链格式:endpoint/存储桶/目录/文件名*///.withPathStyleAccessEnabled(true).withEndpointConfiguration(new com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration(endpoint, null)).withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(ak, sk))).build();log.info("成功\t创建S3客户端");return client;}/*** 获取OBS操作客户端** @return*/private static void createObsClientInstance() {try {if (obsClient == null) {synchronized (ObsClient.class) {if (obsClient == null) {log.info("createObsClientInstance--->bucketName={},ak={},sk={},endPoint={}", bucketName, ak, sk, endPoint);ClientConfiguration clientConfig = new ClientConfiguration();String httpProtocol = getHttpProtocol(endPoint);clientConfig.setProtocol(httpProtocol.equalsIgnoreCase(Protocol.HTTPS.toString()) ? Protocol.HTTPS : Protocol.HTTP);HCPNamespaceClientBuilder builder = HCPClientBuilder.defaultHCPClient();obsClient = builder.withClientConfiguration(clientConfig).withCredentials(new LocalCredentials(ak, sk))// 去除http协议.withEndpoint(endPoint.replace(getHttpProtocol(endPoint) + "://", "")).withNamespace(bucketName).bulid();obsClientMap.put(bucketName, obsClient);}}}} catch (Exception e) {log.error("连接华润对象存储服务器异常:" + e.getMessage(), e);}}/*** 获取上传文件的基础路径** @return url*/public static String getBasisUrl() {//实示例:http协议 + 存储桶名称 + . + endPoint + port + /String basisUrl = getHttpProtocol(endPoint) + "://" + bucketName + "." + endPoint.replace(getHttpProtocol(endPoint) + "://", "") + (StringUtils.isNotBlank(port) ? port + SEPARATOR : "");log.info("getBasisUrl--->" + basisUrl);basisUrl = replaceDomainName(basisUrl);return basisUrl;}/*** 获取上传文件的基础路径** @param bucketName* @return*/public static String getBasisUrl(String bucketName) {//实示例:http协议 + 存储桶名称 + . + endPoint + port + /String basisUrl = getHttpProtocol(endPoint) + "://" + bucketName + "." + endPoint.replace(getHttpProtocol(endPoint) + "://", "") + (StringUtils.isNotBlank(port) ? port + SEPARATOR : "");log.info("getBasisUrl2--->" + basisUrl);basisUrl = replaceDomainName(basisUrl);return basisUrl;}/*** 根据url地址获取存储桶名称** @param url* @return*/public static String getBucketNameByUrl(String url) {if (StringUtils.isNotBlank(url) && StringUtils.isNotBlank(getHttpProtocol(endPoint))&& url.contains(endPoint.replace(getHttpProtocol(endPoint) + "://", ""))) {String str = url.replace(getHttpProtocol(endPoint) + "://", "");return str.substring(0, str.indexOf("."));} else {// 华润只会使用一个存储桶(访问外链替换了域名导致不支持多个存储桶),这里直接返回log.info("getBucketNameByUrl--->返回默认存储桶" + HuaRunOBSUtil.bucketName);return HuaRunOBSUtil.bucketName;}}/*** 获取区域** @param endPoint* @return*/public static String getRegion(String endPoint) {String substring = endPoint.substring(endPoint.indexOf(".") + 1);return substring.substring(0, substring.indexOf("."));}/*** 获取http协议** @param endPoint* @return*/public static String getHttpProtocol(String endPoint) {return endPoint.substring(0, endPoint.indexOf(":"));}/*** 创建存储桶(不确定以下方式是否有用)** @param bucketName* @return*/public static void createBucket(String bucketName, String endPoint) {try {log.info("createBucket.bucketName--->" + bucketName);log.info("createBucket.endPoint--->" + endPoint);if (!headBucket(bucketName)) {ClientConfiguration clientConfig = new ClientConfiguration();String httpProtocol = getHttpProtocol(endPoint);clientConfig.setProtocol(httpProtocol.equalsIgnoreCase(Protocol.HTTPS.toString()) ? Protocol.HTTPS : Protocol.HTTP);HCPNamespaceClientBuilder builder = HCPClientBuilder.defaultHCPClient();HCPNamespace obsClient = builder.withClientConfiguration(clientConfig).withCredentials(new LocalCredentials(ak, sk))// 去除http协议.withEndpoint(endPoint.replace(getHttpProtocol(endPoint) + "://", "")).withNamespace(bucketName).bulid();obsClientMap.put(bucketName, obsClient);}} catch (Exception e) {log.error("createBucket出现异常:" + e.getMessage(), e);}}/*** 创建存储桶** @param bucketName* @return*/public static void createBucket(String bucketName) {try {log.info("createBucket.bucketName--->" + bucketName);if (!headBucket(bucketName)) {S3APIClient.createBucket(bucketName);}} catch (Exception e) {log.error("createBucket出现异常:" + e.getMessage(), e);}}/*** 删除存储桶** @param bucketName* @return*/public static void deleteBucket(String bucketName) {S3APIClient.deleteBucket(bucketName);}/*** 判断存储桶是否存在** @param bucketName* @return*/public static boolean headBucket(String bucketName) {try {return obsClient.doesNamespacesExist(bucketName);} catch (Exception e) {log.error("headBucket出现异常:" + e.getMessage(), e);}return false;}/*** 上传字符** @param bucketName* @param objectName* @param content* @return*/public static ResultBody putObjectByStr(String bucketName, String objectName, String content) {log.info("putObjectByStr--->bucketName={},objectName={},content={}", bucketName, objectName, content);if (StringUtils.isBlank(content)) {return null;}//重新构建objectNameobjectName = buildObjectName(objectName);String errorMsg = "";for (int i = 0; i < 3; i++) {try {S3APIClient.putObject(bucketName, objectName, content);return ResultBody.success(new ObjectBasicInfo("putObjectByStr", objectName));} catch (Exception e) {log.error("putObjectByStr出现异常:" + e.getMessage(), e);errorMsg = e.getMessage();}}return ResultBody.failure(errorMsg);}/*** 上传输入流** @param bucketName* @param objectName* @param inputStream* @return*/public static ResultBody putObjectByInput(String bucketName, String objectName, InputStream inputStream) {log.info("putObjectByInput--->bucketName={},objectName={}", bucketName, objectName);//重新构建objectNameobjectName = buildObjectName(objectName);String errorMsg = "";ObjectMetadata metadata = new ObjectMetadata();for (int i = 0; i < 3; i++) {try {metadata.setContentLength(inputStream.available());S3APIClient.putObject(bucketName, objectName, inputStream, metadata);return ResultBody.success(new ObjectBasicInfo("inputStream", objectName));} catch (Exception e) {log.error("第" + (i + 1) + "次putObjectByInput出现异常:" + e.getMessage(), e);errorMsg = e.getMessage();}}return ResultBody.failure(errorMsg);}/*** 上传文件输入流** @param bucketName* @param objectName* @param fileInputStream* @return*/public static ResultBody putObjectByFileInput(String bucketName, String objectName, FileInputStream fileInputStream) {log.info("putObjectByFileInput--->bucketName={},objectName={}", bucketName, objectName);return putObjectByInput(bucketName, objectName, fileInputStream);}/*** 通过MultipartFile,上传文件** @param bucketName* @param objectName* @param media* @return*/public static ResultBody putObjectByMultipartFile(String bucketName, String objectName, MultipartFile media) throws IOException {log.info("putObjectByMultipartFile--->bucketName={},objectName={}", bucketName, objectName);return putObjectByInput(bucketName, objectName, media.getInputStream());}/*** 上传本地文件** @param bucketName* @param objectName* @param file* @return*/public static ResultBody putObjectByFile(String bucketName, String objectName, File file) {log.info("putObjectByFile--->bucketName={},objectName={}", bucketName, objectName);//重新构建objectNameobjectName = buildObjectName(objectName);String errorMsg = "";for (int i = 0; i < 3; i++) {try {S3APIClient.putObject(bucketName, objectName, file);return ResultBody.success(new ObjectBasicInfo(file.getName(), objectName));} catch (Exception e) {log.error("第" + (i + 1) + "次putObjectByFile出现异常:" + e.getMessage(), e);errorMsg = e.getMessage();}}return ResultBody.failure(errorMsg);}/*** 下载文件到本地** @param bucketName* @param objectName* @param filePath* @return*/public static boolean downloadObject(String bucketName, String objectName, String filePath) throws Exception {log.info("downloadObject--->bucketName={},objectName={},filePath={}", bucketName, objectName, filePath);if (StringUtils.isBlank(filePath)) {return false;}//重新构建objectNameobjectName = buildObjectName(objectName);filePath = filePath.replace("\\", SEPARATOR);InputStream input = null;FileOutputStream fileOutputStream = null;try {S3Object obsObject = null;for (int i = 0; i < 3; i++) {try {// 获取对象obsObject = S3APIClient.getObject(bucketName, objectName);break;} catch (Exception e) {log.error("第" + (i + 1) + "次downloadObject出现异常:" + e.getMessage(), e);}}// 读取对象内容input = obsObject.getObjectContent();if (input == null) {return false;}//获取文件夹路径if (filePath.contains(SEPARATOR)) {String dir = filePath.substring(0, filePath.lastIndexOf(SEPARATOR));File difFile = new File(dir);if (!difFile.exists()) {//创建文件夹boolean mkdirs = difFile.mkdirs();}}File file = new File(filePath);fileOutputStream = new FileOutputStream(file);byte[] b = new byte[1024];int len;while ((len = input.read(b)) != -1) {fileOutputStream.write(b, 0, len);}return true;} finally {if (fileOutputStream != null) {fileOutputStream.close();}if (input != null) {input.close();}}}/*** 获取文件内容** @param bucketName* @param objectName* @return*/public static String getObjectContent(String bucketName, String objectName) throws IOException {log.info("getObjectContent--->bucketName={},objectName={}", bucketName, objectName);//重新构建objectNameobjectName = buildObjectName(objectName);InputStream input = null;ByteArrayOutputStream bos = new ByteArrayOutputStream();try {for (int i = 0; i < 3; i++) {try {// 读取对象内容input = S3APIClient.getObject(bucketName, objectName).getObjectContent();break;} catch (Exception e) {log.error("第" + (i + 1) + "次getObjectContent出现异常:" + e.getMessage(), e);}}byte[] b = new byte[1024];int len;while ((len = input.read(b)) != -1) {bos.write(b, 0, len);}return new String(bos.toByteArray());} catch (Exception e) {log.error("getObjectContent出现异常:" + e.getMessage(), e);} finally {bos.close();if (input != null) {input.close();}}return null;}/*** 获取文件输入流** @param bucketName* @param objectName* @return*/public static InputStream getObject(String bucketName, String objectName) {log.info("getObject--->bucketName={},objectName={}", bucketName, objectName);//重新构建objectNameobjectName = buildObjectName(objectName);for (int i = 0; i < 3; i++) {try {S3Object object = S3APIClient.getObject(bucketName, objectName);return object.getObjectContent();} catch (Exception e) {log.error("第" + (i + 1) + "次getObject出现异常:" + e.getMessage(), e);}}return null;}/*** 列举指定目录的全部对象** @param bucketName* @param directoryPath* @return*/public static ResultBody listAllObjects(String bucketName, String directoryPath) {log.info("listAllObjects--->bucketName={},directoryPath={}", bucketName, directoryPath);List<ObjectDetailInfo> objList = new ArrayList<>();try {HCPNamespace obsClient = obsClientMap.get(bucketName);ListObjectRequest request = new ListObjectRequest(directoryPath).withRecursiveDirectory(true);obsClient.listObjects(request, new ListObjectHandler() {@Overridepublic NextAction foundObject(HCPObjectSummary obj) {ObjectDetailInfo objInfo = new ObjectDetailInfo(obj.getName(),obj.getKey(),obj.getSize(),obj.getType(),DatetimeFormat.ISO8601_DATE_FORMAT.format(new Date(obj.getChangeTime())),obj.getContentHash());objList.add(objInfo);return null;}});} catch (Exception e) {log.error("listAllObjects出现异常:" + e.getMessage(), e);return ResultBody.failure(e.getMessage());}return ResultBody.success(objList);}/*** 删除单个对象** @param bucketName* @param objectName* @return*/public static ResultBody deleteObject(String bucketName, String objectName) {log.info("deleteObject--->bucketName={},objectName={}", bucketName, objectName);//重新构建objectNameobjectName = buildObjectName(objectName);try {HCPNamespace obsClient = obsClientMap.get(bucketName);obsClient.deleteObject(bucketName, objectName);return ResultBody.success();} catch (Exception e) {log.error("deleteObject出现异常:" + e.getMessage(), e);return ResultBody.failure(e.getMessage());}}/*** 复制对象** @param sourceBucketName* @param sourceObjectName* @param destBucketName* @param destObjectName* @return*/public static boolean copyObject(String sourceBucketName, String sourceObjectName,String destBucketName, String destObjectName) {log.info("deleteObject--->sourceBucketName={},sourceObjectName={},destBucketName={},destObjectName={}", bucketName, sourceObjectName, destBucketName, destObjectName);CopyObjectRequest copyObjectRequest = new CopyObjectRequest();copyObjectRequest.withSourceNamespace(sourceBucketName);copyObjectRequest.withSourceKey(sourceObjectName);copyObjectRequest.withTargetNamespace(destBucketName);copyObjectRequest.withTargetKey(destObjectName);try {obsClient.copyObject(copyObjectRequest);return true;} catch (Exception e) {log.error("copyObject出现异常:" + e.getMessage(), e);}return false;}/*** 判断对象是否存在** @param bucketName* @param objectName* @return*/public static boolean doesObjectExist(String bucketName, String objectName) {log.info("deleteObject--->bucketName={},objectName={}", bucketName, objectName);//重新构建objectNameobjectName = buildObjectName(objectName);try {HCPNamespace obsClient = obsClientMap.get(bucketName);return obsClient.doesObjectExist(objectName);} catch (Exception e) {log.error("doesObjectExist出现异常:" + e.getMessage(), e);}return false;}/*** 获取文件外链** @param bucketName* @param objectName* @param expires    单位:秒(s)* @return*/public static String getSignedUrl(String bucketName, String objectName, Long expires) {log.info("getSignedUrl--->bucketName={},objectName={},expires={}", bucketName, objectName, expires);//重新构建objectNameobjectName = buildObjectName(objectName);Date expiration = new Date(System.currentTimeMillis() + (expires * 1000));try {//String e = endPoint.replace(getHttpProtocol(endPoint) + "://", "");//AmazonS3 hs3Client = newS3Client(e, ak, sk);// 生成预签名时间URL url = S3APIClient.generatePresignedUrl(new GeneratePresignedUrlRequest(bucketName, objectName).withExpiration(expiration).withMethod(HttpMethod.GET));String s = url.toString();log.info("这个是api生成的url------------------------------------>" + s);// 由于api返回的是http,这里自行替换为endpoint使用的协议s = s.replace(getHttpProtocol(s) + "://", getHttpProtocol(endPoint) + "://");log.info("替换协议后url------>" + s);s = replaceDomainName(s);return s;} catch (Exception e) {log.error("getSignedUrl出现异常:" + e.getMessage(), e);}return null;}/*** 获取文件外链-url有效时间默认7天** @param bucketName* @param objectName* @return*/public static String getSignedUrl(String bucketName, String objectName) {return getSignedUrl(bucketName, objectName, expire);}/*** 重新构建objectName** @param objectName*/private static String buildObjectName(String objectName) {if (StringUtils.isBlank(objectName)) {return objectName;}//去除开头的/objectName = objectName.startsWith("/") ? objectName.substring(1) : objectName;//去除?后边的参数objectName = objectName.contains("?") ? objectName.substring(0, objectName.indexOf("?")) : objectName;return objectName;}/*** 传入文件访问外链,返回objectName** @param url* @return*/public static String getObjectNameByUrl(String url) {if (StringUtils.isBlank(url)) {return url;}try {url = URLDecoder.decode(url, "UTF-8");} catch (Exception e) {log.error("getObjectNameByUrl获取文件外链失败:" + e.getMessage(), e);}if (url.contains(getBasisUrl())) {// 去除基础路径url = url.replace(getBasisUrl(), "");// 去除?后边的参数url = url.contains("?") ? url.substring(0, url.indexOf("?")) : url;}return url;}/*** 获取华润OBS文件外链** @param redisKey* @param objectName* @return* @throws Exception*/public static String getOBSFileUrl(String redisKey, String objectName) throws Exception {if (StringUtils.isBlank(objectName) || StringUtils.isBlank(redisKey) || OBSUtil.httpRegex(objectName)) {return "";}objectName = URLDecoder.decode(objectName, "UTF-8");//重新构建objectNameobjectName = buildObjectName(objectName);Object o = redisUtil.get(redisKey);String url = o == null ? null : o.toString();if (StringUtils.isNotBlank(url)) {return url;} else {//重新获取urlString signedUrl = getSignedUrl(getBucketName(), objectName, expire);//保存访问url,有效期为6天redisUtil.set(redisKey, signedUrl, 6 * 24 * 60 * 60);return signedUrl;}}/*** 从指定存储桶获取华润OBS文件外链** @param redisKey* @param objectName* @param bucketName* @return* @throws Exception*/public static String getOBSFileUrl(String redisKey, String objectName, String bucketName) throws Exception {if (StringUtils.isBlank(objectName) || StringUtils.isBlank(redisKey) || StringUtils.isBlank(bucketName)) {return "";}//重新构建objectNameobjectName = buildObjectName(objectName);Object o = redisUtil.get(redisKey);String url = o == null ? null : o.toString();if (StringUtils.isNotBlank(url)) {return url;} else {//重新获取urlString signedUrl = getSignedUrl(bucketName, objectName, expire);//保存访问url,有效期为6天redisUtil.set(redisKey, signedUrl, 6 * 24 * 60 * 60);return signedUrl;}}/*** 保存华润OBS文件外链至redis** @param redisKey* @param url* @return*/public static boolean setOBSFileUrl(String redisKey, String url) {Object o = redisUtil.get(redisKey);if (o != null) {String value = o.toString();//只保存新的外链,解决url重复保存导致redis保存的是过期外链的问题if (!value.equals(url)) {//保存访问url,有效期为6天return redisUtil.set(redisKey, url, 6 * 24 * 60 * 60);}} else {//保存访问url,有效期为6天return redisUtil.set(redisKey, url, 6 * 24 * 60 * 60);}return true;}/*** 删除华润OBS文件外链** @param redisKey*/public static void delOBSFileUrl(String redisKey) {//删除访问urlredisUtil.del(redisKey);}/*** 替换域名** @param url* @return*/private static String replaceDomainName(String url){if (StringUtils.isNotBlank(replaceDomainName) && StringUtils.isNotBlank(targetDomainName)) {url = url.replace(targetDomainName, replaceDomainName);log.info("替换域名后url------>" + url);}return url;}public static void setTargetDomainName(String targetDomainName) {HuaRunOBSUtil.targetDomainName = targetDomainName;}public static void setReplaceDomainName(String replaceDomainName) {HuaRunOBSUtil.replaceDomainName = replaceDomainName;}
}

三、对象存储放在内网,如何实现外网访问

如果对象存储是放在内网的,可以按照以下示例配置ngin代理

nginx配置请参考:https://app.rwork.crc.com.cn/docs/dock9zVHp5WcpLYNKfjo5ACbU8g

结合代码中的targetDomainNamereplaceDomainName可实现外网访问

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

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

相关文章

【趣味学算法】05_谁在说谎

注&#xff1a; 本系列仅为个人学习笔记&#xff0c;学习内容为《算法小讲堂》&#xff08;视频传送门&#xff09;&#xff0c;通俗易懂适合编程入门小白&#xff0c;需要具备python语言基础&#xff0c;本人小白&#xff0c;如内容有误感谢您的批评指正 现有 张三、李四和 王…

2024年GitHub标星2-9K的Android基础——高级面试题合集

3、横竖屏切换时候 Activity 的生命周期 4、AsyncTask 的缺陷和问题&#xff0c;说说他的原理。 5、onSaveInstanceState() 与 onRestoreIntanceState() Android高级面试题 1、你们做了哪些稳定性方面的优化&#xff1f; 2、性能稳定性是怎么做的&#xff1f; 3、业务稳定性如…

python 修改3d旋转顺序

目录 python实现修改3d旋转顺序 矩阵批量计算 因为矩阵相乘不能交换,所以3d旋转顺序不能交换。 python实现修改3d旋转顺序 import numpy as np from scipy.spatial.transform import Rotation as Rdef convert_rotation(y, x, z, from_order, to_order):# 创建一个旋转对象…

使用Docker管理linux容器

文章目录 一、使用docker管理镜像 二、使用docker管理容器 一、使用docker管理镜像 1、安装操作系统&#xff0c;我安装的是centOS 7 &#xff0c;因为centos7有着非常丰富的软件仓库&#xff0c;方便后续安装与docker相关的软件。 2、初始化设置&#xff0c; 关闭防火墙 关闭…

独家原创!微电网OR综合能源系统用户用电行为分析程序代码!

适用平台&#xff1a;MatlabYalmipCplex 程序以含分布式新能源、储能、微型燃气轮机作为主要电力来源&#xff0c;以照明设备、电视、洗衣机和空调等主要家庭用电设备作为电负荷&#xff0c;仿真了3种典型家庭用户的用电行为。程序算例丰富、注释清晰、干货满满&#xff0c;可…

TCP收发——计算机网络——day02

今天主要讲了TCP的收发 TCP发端步骤 ①socket ②connect ③send ④closeTCP收端步骤 ①socket ②bind ③listen ④accept ⑤recv ⑥clise其函数主要有 connect int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);功能:发送链接请求参数:sockfd:套接…

BCI-自我QA 记录

学习中的 Q&A 记录 Q: 事件驱动的语音感知的两种机制 A: 第一种机制是基于对声学能量的快速增加进行感知&#xff08;时域分析&#xff09;。它关注的是声音在时间上的动态变化&#xff0c;特别是声学能量的迅速增加。这种机制可能用来检测语音中的重要事件&#xff0c;如音…

Ribbon简单使用

Ribbon是Netflix发布的云中间层服务开源项目&#xff0c;其主要功能是提供客户端实现负载均衡算法。Ribbon客户端组件提供一系列完善的配置项如连接超时&#xff0c;重试等。简单的说&#xff0c;Ribbon是一个客户端负载均衡器&#xff0c;我们可以在配置文件中Load Balancer后…

React入门 学习全记录(适合和我一样有Vue经验想学习react的同学~)

前端目前的三大框架&#xff1a;Vue、React、Angular比较 都采用了组件化开发的方式&#xff0c;都是基于MVVM的框架有着虚拟DOM&#xff0c;Vue 和 Angular 都采用了响应式设计的方式&#xff0c;当数据发生变化时会自动更新视图。React 和 Angular 的复杂性也使得它们更加适…

个人博客系列-后端项目-用户注册功能(7)

介绍 用户注册API的主要流程&#xff1a;1.前端用户提交用户名&#xff0c;密码 2. 序列化器校验用户名&#xff0c;密码是否合法。3.存入数据库。4.签发token 创建序列化器 from rest_framework import serializers from rest_framework_simplejwt.serializers import Toke…

Map接口

Map接口 Map接口&#xff0c;双列集合&#xff08;每个元素&#xff0c;包含一个键&#xff08;key&#xff09;&#xff0c;一个值对象&#xff08;Value&#xff09;&#xff0c;键与值之间的对应关系叫做映射&#xff09;&#xff0c;Map中每个元素的键不允许重复&#xff…

解决使用torch.cuda.empty_cache()仍然GPU显存无法释放的问题

在开发的过程中&#xff0c;程序已经关闭&#xff0c;但是GPU显存无法释放&#xff0c;在使用pytorch写程序的时候, 有时候会在控制台终止掉正在运行的程序&#xff0c;但是有时候程序已经结束了&#xff0c;nvidia-smi也看到没有程序了&#xff0c;但是GPU的内存并没有释放&a…

记录一次大厂面试题

回流和重绘 浏览器渲染页面步骤&#xff1a; 处理HTML标记并构建DOM树处理css标记并构建CSSOM树将DOM和CSSOM合并成一个渲染树根据渲染树来布局以计算每个节点的几何信息将各个节点绘制到屏幕上 回流&#xff1a;当Render树中部分或全部元素的尺寸、布局、隐藏等改变&#xf…

C++知识点总结(24):栈的真题

概览 P1044 ★★★☆☆ [NOIP2003 普及组] 栈1. 审题题目背景题目描述输入格式输出格式样例1 2. 思路3. 参考答案3.1 卡特兰公式3.2 前缀和 P1044 ★★★☆☆ [NOIP2003 普及组] 栈 1. 审题 题目背景 栈是计算机中经典的数据结构&#xff0c;简单的说&#xff0c;栈就是限制…

算法:数据结构顺序表表的插入、删除和查找

#include <iostream> #include <stdio.h> #define MaxSize 50 typedef int ElemType; typedef struct {ElemType data[MaxSize];int length; }SqList; bool ListInsert(SqList &L,int i,ElemType e)//插入数据 {if(i<1 || i>L.length1)//判断插入的位置是…

自动化运维利器Ansible基础(环境部署)

Ansible 介绍及安装 1. 介绍 Ansible 是⼀个 IT ⾃动化⼯具。它能配置系统、部署软件、编 排更复杂的 IT 任务&#xff0c;如连续部署或零停机时间滚动更新。 Ansible ⽤ Python 编写&#xff0c;尽管市⾯上已经有很多可供选择的 配置管理解决⽅案&#xff08;例如 Salt、Pupp…

Aigtek高压功率放大器设计参数有哪些

高压功率放大器是一种用于放大高频信号的电子设备&#xff0c;广泛应用于通信、雷达、无线电等领域。它能够将输入信号的幅度放大到较高的水平&#xff0c;以便传输或驱动其他设备。 在设计高压功率放大器时&#xff0c;需要考虑以下几个重要参数&#xff1a; 频率范围&#xf…

代码随想录 二叉树—二叉树的层序遍历Ⅱ

思路&#xff1a;就是在上一个题的基础上将result最后翻转了一下&#xff0c;这样就可以实现自下而上的层序遍历。 知识点&#xff1a;stack和queue&#xff0c;也就是栈和队列&#xff0c;是push&#xff1b; 栈stack&#xff1a;push()&#xff0c;pop()&#xff0c;top()&a…

ELK 安装部署

文章目录 1.日志收集规划2.Elasticsearch部署2.1.Elasticsearch安装2.2.Elasticsearch-head安装2.3.Elasticsearch设置分片数2.4.elasticsearch健康检查 3.Kibana部署4.Logstash部署5.Filebeat部署 开源中间件 # Elastic Stackhttps://iothub.org.cn/docs/middleware/ https:/…

工会排队模式:引领创新消费体验的新潮流

在互联网和电子商务的浪潮下&#xff0c;消费者的购物需求与期待正在持续升级。为了迎合这一趋势&#xff0c;工会排队模式应运而生&#xff0c;以其独特的消费体验方式引领市场潮流。 工会排队模式打破了传统电商的桎梏&#xff0c;通过现金返还机制为购物赋予了新的定义。这一…