阿里云OSS图片上传下载以及删除

发布时间 2023-08-17 22:59:23作者: ChenQ2

概述

  • 笔者也不知道该怎么概述,在下面代码中主要就是几个参数比较难以搞懂,搞懂了参数就不难使用。那么开始吧!

Maven地址

  <!-- 阿里云OSS -->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.16.1</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.3</version>
        </dependency>

必要参数

accessKeyId
  • accessKeyId 是在登录阿里云官网时需要创建的,谁交给你这个开发任务那么就问谁去要。假设对方不知道,就要问对方要购买阿里云OSS服务的账号密码,然后在去控制台查看,具体查看方法可以百度。
accessKeySecret
  • accessKeySecret 也是在登录阿里云官网时需要创建的,获取方法同上!
bucket
  • Bucket 是在购买 OSS 服务的后要创建的,在哪里创建自行百度。
endPoint
  • endPoint 是在购买 OSS 服务的后要创建的,在哪里创建自行百度。在下面图片的两个标记中,在点击确定按钮之前需要把这个两个参数保存好,虽然后期也可以查看,但是比较麻烦。

OSS配置类

  • 笔者是把以上参数配置在 Springbootyml 配置文件中,记得在保存的endPoint前加上https。以下配置仅供参考
## 阿里云配置
aliyunoss:
  accessKeyId: LTAI5t8LBSMKX2R8ZLtn****
  accessKeySecret: ekwm3JDe9wUbzuPLA8MF5f8tmT****
  bucket: blog****pig
  endPoint: https://oss-cn-beijing.aliyuncs.com
@Data
@Configuration
@ConfigurationProperties(prefix = "aliyunoss")
public class ALiYunOSSProperties {


    private String accessKeyId;

    private String accessKeySecret;

    private String bucket;

    private String endPoint;

}

具体实现代码

顶级接口
/**
 * @author unknown
 * @since 2023/08/12 13:18
 */
public interface BlogFileService {

    /**
     * <P>上传图片</P>>
     *
     * @param file 文件对象
     * @return
     */
    String uploadPictureFile(MultipartFile file) throws ClientException, IOException;


    /**
     * <P>下载文件</P>
     *
     * @param uri 图片完整路径
     * @param request
     * @param response
     */
    InputStream downloadPictureFile(String uri, HttpServletRequest request, HttpServletResponse response);


    /**
     * <P>删除图片</P>
     * @param url 图片完整路径
     */
    void deletePictureFile(String url);
}
OSS实现类
/**
 * @author unknown
 * @since 2023/08/12 13:30
 */
@Slf4j
@Service
public class AliYunOSSFileImpl implements BlogFileService {


    // Spring中读取配置文件的方法
    @Value("aliyunoss.accessKeyId")
    private String accessKeyId;

    @Value("aliyunoss.accessKeySecret")
    private String accessKeySecret;

    @Value("aliyunoss.bucket")
    private String bucket;

    @Value("aliyunoss.endPoint")
    private String endPoint;

    
    @Autowired
    private ALiYunOSSProperties aLiYunOSSProperties;

    /**
     * <P>阿里云OSS图片上传</P>
     *
     * @param file 文件对象
     * @return 图片URL
     * @throws IOException ClientException
     * @see <a href="https://help.aliyun.com/zh/oss/developer-reference/oss-java-configure-access-credentials?spm=a2c4g.11186623.0.0.506cb417OuUTJk#8c51f4c0f0v92"> 请认真阅读官方文档-开发参考
     */
    @Override
    public String uploadPictureFile(MultipartFile file){

        // 获取文件名
        String originalFilename = file.getOriginalFilename();

        // 获取配置文件参数
        String accessKeyId = aLiYunOSSProperties.getAccessKeyId();
        String accessKeySecret = aLiYunOSSProperties.getAccessKeySecret();
        String endPoint = aLiYunOSSProperties.getEndPoint();
        String bucket = aLiYunOSSProperties.getBucket();

        // 访问密钥配置访问凭证
        CredentialsProvider credentialsProviderCode = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endPoint, credentialsProviderCode);

        try {
            // 上传图片
            ossClient.putObject(bucket, originalFilename, new ByteArrayInputStream(file.getBytes()));
            // 获取图片URL
            Date expiration = new Date(System.currentTimeMillis() + 3600 * 24 * 365 * 15 * 1000L);
            return ossClient.generatePresignedUrl(bucket, originalFilename, expiration).toString();

        } 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());
            throw new BlogRuntimeException(ResultCode.PHOTO_UPLOAD_FAILED, oe.getMessage());
        } catch (com.aliyun.oss.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());
            throw new BlogRuntimeException(ResultCode.PHOTO_UPLOAD_FAILED, ce.getMessage());
        }catch (IOException ioException){
            throw new BlogRuntimeException(ResultCode.PHOTO_UPLOAD_FAILED, ioException.getMessage());
        } finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }

    }

    /**
     * <P>阿里云OSS图片下载</P>
     *
     * @param url      图片完整路径,在数据库存储的路径,如果丢在浏览器可以直接访问,那么就可以正常使用
     * @param request  request
     * @param response response
     * @return InputStream
     */
    @Override
    public InputStream downloadPictureFile(String url, HttpServletRequest request, HttpServletResponse response) {

        // 获取配置文件参数
        String accessKeyId = aLiYunOSSProperties.getAccessKeyId();
        String accessKeySecret = aLiYunOSSProperties.getAccessKeySecret();
        String endPoint = aLiYunOSSProperties.getEndPoint();
        String bucket = aLiYunOSSProperties.getBucket();

        // 访问密钥配置访问凭证
        CredentialsProvider credentialsProviderCode = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
        OSS ossClient = new OSSClientBuilder().build(endPoint, credentialsProviderCode);

        // 切割图片上传的url,获取上传时的文件名称,这一定很重要,你上传的文件是什么名字,那么就要用什么名字作为Key来访问
        String fileName = url.substring(url.indexOf("/", 8) + 1, url.indexOf("?"));

        try {
            OSSObject ossObject = ossClient.getObject(new GetObjectRequest(bucket, fileName));
            InputStream objectContent = ossObject.getObjectContent();
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024];
            int len;
            while ((len = objectContent.read(buffer)) > -1) {
                outputStream.write(buffer, 0, len);
            }
            // 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
            outputStream.flush();
            outputStream.close();
            objectContent.close();
            return new ByteArrayInputStream(outputStream.toByteArray());

        } 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());
            throw new BlogRuntimeException(ResultCode.FILE_DOES_NOT_EXIST);
        } 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());
            throw new BlogRuntimeException(ResultCode.FILE_DOES_NOT_EXIST);
        } catch (IOException e) {
            log.error("AliYunOssServiceImpl downloadFile", e);
            throw new BlogRuntimeException(ResultCode.FILE_DOES_NOT_EXIST);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }


    /**
     * <P>图片删除</P>
     * @param url 图片完整路径,在数据库存储的路径,如果丢在浏览器可以直接访问,那么就可以正常使用
     */
    @Override
    public void deletePictureFile(String url) {

        // 获取配置文件参数
        String accessKeyId = aLiYunOSSProperties.getAccessKeyId();
        String accessKeySecret = aLiYunOSSProperties.getAccessKeySecret();
        String endPoint = aLiYunOSSProperties.getEndPoint();
        String bucket = aLiYunOSSProperties.getBucket();

        // 访问密钥配置访问凭证
        CredentialsProvider credentialsProviderCode = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
        OSS ossClient = new OSSClientBuilder().build(endPoint, credentialsProviderCode);

        // 切割图片上传的url,获取上传时的文件名称,这一定很重要,你上传的文件是什么名字,那么就要用什么名字作为Key来访问
        String fileName = url.substring(url.indexOf("/", 8) + 1, url.indexOf("?"));

        ossClient.deleteObject(bucket, fileName);
        ossClient.shutdown();
    }
}
Controller层
  • 以下代码唯一有价值的参数怎么传递
/**
 * @author unknown
 * @since 2023/08/12 13:43
 */
@Slf4j
@RestController
@RequestMapping("/blog/version-1.0/file")
public class FileController {

    @Autowired
    private BlogFileService aLiYunOSSFile;

    /**
     * <P>图片上传</P>
     *
     * @param file 图片对象
     * @return 图片URL
     * @throws ClientException 阿里云OSS异常
     */
    @PostMapping("/uploadPicture")
    public Result<String> uploadPicture(MultipartFile file) throws ClientException, IOException {

        log.info("FileController uploadPicture Request param: {}", file);
        String picture = aLiYunOSSFile.uploadPictureFile(file);
        log.info("FileController uploadPicture Response PictureURL:  {}", picture);
        return ResultBuilder.successResult(picture);
    }

    /**
     * <P>删除图片</P>
     * @param url 图片URL
     * @return Result
     */
    @DeleteMapping("/deletePicture")
    public Result<String> deletePicture(@RequestParam String url){

        log.info("FileController uploadPicture Request param: {}", url);
        aLiYunOSSFile.deletePictureFile(url);
        return ResultBuilder.successResult();
    }


    /**
     * <P>图片下载到本地</P>
     *
     * @param url 图片地址
     * @param request
     * @param response
     * @return 输出流
     */
    @GetMapping(value = "/downloadPicture", produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_JSON_VALUE})
    public Result<String> downloadPicture(@RequestParam String url, HttpServletRequest request, HttpServletResponse response){

        log.info("FileController downloadPicture Request param: {}", url);

        InputStream inputStream = null;
        BufferedOutputStream outputStream = null;

        // 切割url获取上传时的文件名称
        String fileName = url.substring(url.indexOf("/", 8) + 1, url.indexOf("?"));

        try {
            inputStream = aLiYunOSSFile.downloadPictureFile(url, request, response);
            response.reset();
            response.setHeader("Content-disposition", "attachment;filename=" + setFileDownloadHeader(request, fileName));
            response.setContentType("application/octet-stream;charset=UTF-8");
            outputStream = new BufferedOutputStream(response.getOutputStream());
            if (inputStream != null) {
                int len;
                while ((len = inputStream.read()) != -1) {
                    outputStream.write(len);
                    outputStream.flush();
                }
            }
        } catch (Exception e) {
            log.error("FileController downloadFile error", e);
        } finally {
            if (Objects.nonNull(inputStream)) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (Objects.nonNull(outputStream)) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return ResultBuilder.successResult();
    }

    public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {
        final String agent = request.getHeader("USER-AGENT");
        String filename = fileName;
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, StandardCharsets.UTF_8);
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            filename = new String(fileName.getBytes(), "ISO8859-1");
        } else if (agent.contains("Chrome")) {
            // google浏览器
            filename = URLEncoder.encode(filename, StandardCharsets.UTF_8);
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, StandardCharsets.UTF_8);
        }
        return filename;
    }
}

Tips

  • 对读者的一些小建议
    • 读者任务时间不紧迫,请结合官网文档进行查看和Debug本代码。
      • 开发参考-SDK参考-Java
    • 时间紧迫,请直接粘贴复制即用。
  • 还有什么问题可以给笔者发邮件,599303650@qq.com