Jelajahi Sumber

阿里云OSS apk文件上传

marxjaw 3 bulan lalu
induk
melakukan
66f69d4df6

+ 1 - 1
yt-app/app-service/src/main/resources/mapper/AppUserMapper.xml

@@ -258,7 +258,7 @@
         from yt_dyz_user
         where wx_open_id = #{openid}
     </select>
-    <select id="getByDeviceId" resultType="com.ytpm.app.model.YtDyzUser">
+    <select id="getByDeviceId" resultType="java.lang.String">
         select
             platform_id
         from yt_dyz_user

+ 6 - 0
yt-middle/middle-platform/pom.xml

@@ -27,6 +27,12 @@
             <artifactId>guava</artifactId>
             <version>32.0.1-android</version>
         </dependency>
+        <!-- 阿里云对象存储 -->
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>3.17.4</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 18 - 64
yt-middle/middle-platform/src/main/java/com/ytpm/middle/service/impl/AttachServiceImpl.java

@@ -1,98 +1,52 @@
 package com.ytpm.middle.service.impl;
 
-import cn.hutool.core.util.IdUtil;
 import com.ytpm.attach.Attach;
 import com.ytpm.attach.Image;
-import com.ytpm.handle.CustomerException;
-import com.ytpm.middle.oss.OssProperties;
-import com.ytpm.middle.oss.OssUtil;
 import com.ytpm.middle.service.AttachService;
+import com.ytpm.middle.util.AliOSSUtil;
 import lombok.extern.slf4j.Slf4j;
-import net.coobird.thumbnailator.Thumbnails;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.io.File;
 import java.io.IOException;
 
 @Slf4j(topic = "attach-service")
 @Service
 public class AttachServiceImpl implements AttachService {
 
-    @Autowired
-    OssProperties properties;
+    private static String endpoint;
+
+    @Value("${oss.aliyun.endpoint}")
+    private void setEndpoint(String endpointCon) {
+        endpoint = endpointCon;
+    }
 
     @Override
     public Attach uploadFile(MultipartFile multipartFile) {
 
         String originFilename = multipartFile.getOriginalFilename();
         Attach attach = new Attach();
-        String ossName = upload(multipartFile, properties, false);
         attach.setName(originFilename);
-        attach.setOssName(ossName);
-        attach.setUrl(OssUtil.getUrl(ossName, properties));
+        try {
+            attach.setUrl(endpoint+"/"+AliOSSUtil.uploadAdvise(multipartFile.getInputStream(),originFilename));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
         attach.setFileSize(multipartFile.getSize());
         return attach;
     }
 
     @Override
     public Image uploadImage(MultipartFile multipartFile) {
-        String ossName = upload(multipartFile, properties, true);
-
+        String imgName = multipartFile.getOriginalFilename();
         Image image = new Image();
-        image.setOssName(ossName);
-        image.setUrl(OssUtil.getUrl(ossName, properties));
-        return image;
-    }
-
-    /**
-     * 文件上传
-     *
-     * @param multipartFile 文件
-     * @param properties    存储配置
-     * @param isImage       是否为图片
-     * @return 文件ossName
-     */
-    private String upload(MultipartFile multipartFile, OssProperties properties, Boolean isImage) {
-        String originFilename = multipartFile.getOriginalFilename();
-        String suffix = originFilename.substring(originFilename.lastIndexOf("."));
-
-        if (isImage) {
-            suffix = suffix.toUpperCase();
-            //图片
-            if (!".JPEG,.JPG,.PNG".contains(suffix)||suffix.equals(".")||suffix.equals(",")) {
-                throw new CustomerException("格式类型错误");
-            }
-        }
-
-        String folder = System.getProperty("java.io.tmpdir");
-        File file = new File(folder + File.separator + IdUtil.fastSimpleUUID() + suffix);
-
+        image.setOssName(imgName);
         try {
-            multipartFile.transferTo(file);
-            //压缩图片
-            compressFile(file, suffix);
+            image.setUrl(endpoint+"/"+AliOSSUtil.uploadAdvise(multipartFile.getInputStream(), imgName));
         } catch (IOException e) {
-            log.error("文件上传失败:", e);
-            throw new CustomerException(e.getMessage());
-        }
-
-        return OssUtil.upload(file, properties);
-    }
-
-    private void compressFile(File file, String suffix) {
-        //2、大于2M的图片需要压缩大小
-        long fileSize = file.length();
-        if (".JPEG,.JPG,.PNG".contains(suffix) && fileSize > 1024 * 1024 * 2) {
-            try {
-                Thumbnails.of(file)
-                        .scale(0.2)
-//                        .outputQuality(0.2f)
-                        .toFile(file);
-            } catch (IOException e) {
-                log.error("压缩报错了:", e);
-            }
+            throw new RuntimeException(e);
         }
+        return image;
     }
 }

+ 373 - 0
yt-middle/middle-platform/src/main/java/com/ytpm/middle/util/AliOSSUtil.java

@@ -0,0 +1,373 @@
+package com.ytpm.middle.util;
+
+import com.aliyun.oss.ClientBuilderConfiguration;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.common.auth.Credentials;
+import com.aliyun.oss.common.auth.DefaultCredentialProvider;
+import com.aliyun.oss.common.auth.DefaultCredentials;
+import com.aliyun.oss.common.comm.Protocol;
+import com.aliyun.oss.common.comm.SignVersion;
+import com.aliyun.oss.model.Bucket;
+import com.aliyun.oss.model.DeleteObjectsRequest;
+import com.aliyun.oss.model.DeleteObjectsResult;
+import com.aliyun.oss.model.GetObjectRequest;
+import com.aliyun.oss.model.ListObjectsRequest;
+import com.aliyun.oss.model.OSSObject;
+import com.aliyun.oss.model.OSSObjectSummary;
+import com.aliyun.oss.model.ObjectListing;
+import com.aliyun.oss.model.ObjectMetadata;
+import com.aliyun.oss.model.PutObjectRequest;
+import com.aliyun.oss.model.PutObjectResult;
+import com.aliyun.oss.model.UploadFileRequest;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Date;
+import java.util.List;
+
+@Component
+public class AliOSSUtil {
+
+    private static String endpoint;
+
+    @Value("${oss.aliyun.endpoint}")
+    private void setEndpoint(String endpointCon) {
+        endpoint = endpointCon;
+    }
+
+    private static String accessKeyId;
+
+    @Value("${oss.aliyun.accessKeyId}")
+    private void setAccessKeyId(String accessKeyIdCon) {
+        accessKeyId = accessKeyIdCon;
+    }
+
+    private static String accessKeySecret;
+
+    @Value("${oss.aliyun.accessKeySecret}")
+    private void setAccessKeySecret(String accessKeySecretCon) {
+        accessKeySecret = accessKeySecretCon;
+    }
+
+    private static String bucketName;
+
+    @Value("${oss.aliyun.bucketName}")
+    private void setBucketName(String bucketNameCon) {
+        bucketName = bucketNameCon;
+    }
+
+
+    /**
+     * 针对MultipartFile类型
+     *
+     * @param multipartFile 前端传回的MultipartFile类型的数据
+     * @return java.lang.String 返回该文件的访问链接
+     */
+    public static String upload(MultipartFile multipartFile, String fileName) throws IOException {
+        // 获取上传的文件的输入流
+        InputStream inputStream = multipartFile.getInputStream();
+        return upload(inputStream, fileName);
+    }
+    /**
+     * 上传广告平台文件
+     */
+    public static String uploadAdvise(InputStream inputStream, String fileName) {
+        // 创建 ClientBuilderConfiguration 实例,用于配置 OSS 客户端参数
+        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
+        // 设置签名算法版本为 V4
+        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
+        // 设置使用 HTTPS 协议访问 OSS,保证传输安全性
+        clientBuilderConfiguration.setProtocol(Protocol.HTTPS);
+
+        Credentials credentials = new DefaultCredentials(accessKeyId,accessKeySecret);
+        DefaultCredentialProvider provider = new DefaultCredentialProvider(credentials);
+        // 创建 OSS 客户端实例
+        clientBuilderConfiguration.setSupportCname(true);// 请注意,设置true开启CNAME选项。
+        OSS ossClient = OSSClientBuilder.create()
+                .clientConfiguration(clientBuilderConfiguration)
+                .endpoint(endpoint)
+                .credentialsProvider(provider)
+                .clientConfiguration(clientBuilderConfiguration)
+                .region("cn-nanjing")
+                .build();
+
+        try {
+            ossClient.putObject(new PutObjectRequest(bucketName, fileName, inputStream));
+        }
+        finally {
+            ossClient.shutdown();
+        }
+
+        return fileName;
+    }
+
+    /**
+     * 针对Base64类型
+     *
+     * @param base64 Base64字符串,标准的Base64字符串,例如data:image/png;base64,iVBORw0...
+     * @return java.lang.String 返回该文件的访问链接
+     */
+    public static String upload(String base64) {
+        // 获取上传的文件的输入流
+        byte[] bytes = Base64.getDecoder().decode(base64.split(",")[1]);
+        InputStream inputStream = new ByteArrayInputStream(bytes);
+        // 获取文件名称
+        String fileName = base64.substring(base64.indexOf(":") + 1, base64.indexOf(";")).replace("/", ".");
+
+        return upload(inputStream, fileName);
+    }
+
+    /**
+     * 查询所有文件名称
+     *
+     * @param path 相对于阿里云bucket存储空间的文件路径
+     * @return java.util.List<java.lang.String> 该路径下所有文件的名称
+     * <p>
+     * 注:首先会获取根文件的名称
+     */
+    public static List<String> listFileName(String path) {
+        List<String> res = new ArrayList<>();
+        // 构造ListObjectsRequest请求。
+        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
+
+        // 设置prefix参数来获取fun目录下的所有文件。
+        listObjectsRequest.setPrefix(path);
+
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+        // 列出文件。
+        ObjectListing listing = ossClient.listObjects(listObjectsRequest);
+        // 遍历所有文件
+        for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) {
+            System.out.println(objectSummary.getKey());
+        }
+        // 关闭OSSClient。
+        ossClient.shutdown();
+        return res;
+    }
+
+    /**
+     * 查询所有文件的url
+     *
+     * @param path 相对于阿里云bucket存储空间的文件路径
+     * @return java.util.List<java.lang.String> 返回路径下所有文件的url
+     * <p>
+     * 注:首先会获取根文件夹的url,且根文件夹的url无法访问
+     */
+    public static List<String> listFileUrl(String path) {
+        List<String> res = new ArrayList<>();
+
+        // 构造ListObjectsRequest请求
+        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
+
+        // 设置prefix参数来获取fun目录下的所有文件。
+        listObjectsRequest.setPrefix(path);
+
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+        // 列出文件。
+        ObjectListing listing = ossClient.listObjects(listObjectsRequest);
+        // 遍历所有文件。
+
+        for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) {
+            //文件访问路径
+            Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 100);
+            URL url = ossClient.generatePresignedUrl(bucketName, objectSummary.getKey(), expiration);
+            res.add(url.toString());
+        }
+        // 关闭OSSClient。
+        ossClient.shutdown();
+        return res;
+    }
+
+    /**
+     * 判断文件是否存在
+     *
+     * @param objectName 相对于阿里云bucket存储空间的文件路径和文件名称
+     * @return boolean 存在返回true,存在返回false
+     */
+    public static boolean isFileExist(String objectName) {
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+        boolean res = ossClient.doesObjectExist(bucketName, objectName);
+        return res;
+    }
+
+    /**
+     * 通过文件名称(包括路径)下载文件
+     *
+     * @param objectName    相对于阿里云bucket存储空间的文件路径和文件名称
+     * @param localFileName 下载的路径和文件名称
+     */
+    public static void downloadFile(String objectName, String localFileName) {
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+        // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
+        ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(localFileName));
+        // 关闭OSSClient。
+        ossClient.shutdown();
+    }
+
+    /**
+     * 删除文件或目录
+     *
+     * @param objectName 相对于阿里云bucket存储空间的文件路径和文件名称
+     */
+    public static void deleteFile(String objectName) {
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        ossClient.deleteObject(bucketName, objectName);
+        ossClient.shutdown();
+    }
+
+    /**
+     * 批量删除文件或目录
+     *
+     * @param keys 相对于阿里云bucket存储空间的文件路径和文件名称
+     */
+    public static void deleteFiles(List<String> keys) {
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+        // 删除文件。
+        DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(keys));
+        List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
+
+        ossClient.shutdown();
+    }
+
+    /**
+     * 创建文件夹
+     *
+     * @param folder 文件夹名称。注:文件夹名称后面需要添加“/”,否则创建的是文件,并非文件夹。
+     * @return java.lang.String 相对于阿里云bucket存储空间的文件夹路径
+     */
+    public static String createFolder(String folder) {
+        // 文件夹名
+        final String keySuffixWithSlash = folder;
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+        // 判断文件夹是否存在,不存在则创建
+        if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
+            // 创建文件夹
+            ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
+            // 得到文件夹名
+            OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
+            String fileDir = object.getKey();
+            ossClient.shutdown();
+            return fileDir;
+        }
+
+        return keySuffixWithSlash;
+    }
+
+    /**
+     * 文件上传,文件上传后会将文件放置在当前日期的目录中,如:2022-07-08/1_1657251247153.png
+     *
+     * @param inputStream 上传文件的流
+     * @param fileName    文件名称,命名规则是:文件名+当前时间戳+后缀
+     * @return java.lang.String 返回该文件的访问链接
+     */
+    private static String upload(InputStream inputStream, String fileName) {
+        // 避免文件被覆盖,为上传文件名称添加时间戳
+        int i = fileName.lastIndexOf(".");
+        String suffix = fileName.substring(i);
+        fileName = fileName.substring(0, i) + "-" + System.currentTimeMillis() + suffix;
+
+        // 如果需要上传时设置存储类型与访问权限
+        ObjectMetadata metadata = new ObjectMetadata();
+        metadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
+
+        // 上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
+        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream);
+        putObjectRequest.setMetadata(metadata);
+
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+        ossClient.putObject(putObjectRequest);
+
+        // 关闭ossClient
+        ossClient.shutdown();
+        // 把上传到oss的路径返回
+        return fileName;
+    }
+
+    public static String upload1(InputStream inputStream, String fileName) {
+        // 避免文件被覆盖,为上传文件名称添加时间戳
+        fileName = fileName + "-" + System.currentTimeMillis();
+
+        // 2. 设置文件的 Content-Type
+        ObjectMetadata metadata = new ObjectMetadata();
+        metadata.setContentType(getContentType("png"));
+
+        // 3. 上传文件到OSS,指定文件路径(bucketName 是 OSS 存储桶名称)
+        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream);
+        putObjectRequest.setMetadata(metadata);
+
+        // 4. 创建 OSS 客户端
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+        // 5. 上传文件
+        ossClient.putObject(putObjectRequest);
+
+        // 6. 关闭 OSS 客户端
+        ossClient.shutdown();
+        // 把上传到oss的路径返回
+        return fileName;
+    }
+
+    private static String getContentType(String FileNameExtension) {
+        if (FileNameExtension.equalsIgnoreCase(".bmp")) {
+            return "image/bmp";
+        }
+        if (FileNameExtension.equalsIgnoreCase(".gif")) {
+            return "image/gif";
+        }
+        if (FileNameExtension.equalsIgnoreCase(".jpeg") ||
+                FileNameExtension.equalsIgnoreCase(".jpg") ||
+                FileNameExtension.equalsIgnoreCase(".png")
+        ) {
+            return "image/jpg";
+        }
+        return "image/jpg";
+    }
+
+    public static String uploadToOSS(BufferedImage qrImage, String fileName) {
+        try {
+            // 设置文件的 MIME 类型
+            String fileExtension = fileName.substring(fileName.lastIndexOf("."));
+            ObjectMetadata metadata = new ObjectMetadata();
+            metadata.setContentType(getContentType(fileExtension));  // 设置上传文件的 MIME 类型
+
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ImageIO.write(qrImage, "PNG", baos);
+
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(baos.toByteArray());
+
+            // 使用 OSSClient 上传文件
+            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream);
+            putObjectRequest.setMetadata(metadata);  // 设置文件的元数据
+            ossClient.putObject(putObjectRequest);
+
+            inputStream.close();
+            ossClient.shutdown();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        // 返回上传到OSS的路径
+        return "https://" + bucketName + "." + endpoint + "/" + fileName;
+    }
+
+}

+ 2 - 2
yt-middle/middle-platform/src/main/resources/mapper/ApkMapper.xml

@@ -40,9 +40,9 @@
             <if test="appType !=null">
                 and ya.app_type = #{appType}
             </if>
-            GROUP BY
-            ya.app_id
         </where>
+        GROUP BY
+        ya.app_id
     </select>
 
     <insert id="insertOne">

+ 1 - 1
yt-middle/middle-platform/src/main/resources/mapper/AppMapper.xml

@@ -52,7 +52,7 @@
             me.legal,
             me.concat_phone
         from yt_platform_user_app pua
-        join yt_middle_enterprise me on pua.user_id = me.user_id
+        left join yt_middle_enterprise me on pua.user_id = me.user_id
         <where>
             pua.available = 1
             <if test="appType != null">