JAVA集成阿里云OSS对象存储

JAVA集成阿里云OSS对象存储

  • 1 : 配置集成
    • 1.1、对象存储OSS
  • 2 : 代码配置
    • 2.1、说明
    • 2.2、配置文件
    • 2.3、加载配置文件代码
    • 2.4、封装统一的DTO
    • 2.5、OSS上传Controller
    • 2.6、OSS上传Service
    • 2.7、OSS上传ServiceImpl
  • 3 : 测试
    • 3.1、文件上传
    • 3.2、文件迁移
  • 4 : 总结
    • 4.1、参考资料
    • 4.2、注意事项
    • 4.3、源码链接

1 : 配置集成

1.1、对象存储OSS

这就不用说了,从阿里云平台花钱买OSS对象存储就行了。
然后在bucket列表中创建自己使用的bucket即可。
比如创建:oss-test
然后从概览中找到 Access Key
JAVA集成阿里云OSS对象存储_第1张图片
JAVA集成阿里云OSS对象存储_第2张图片
然后就可以看到对应的id和key了。
JAVA集成阿里云OSS对象存储_第3张图片

这个时候,就有了四个参数
1、access-key:就是刚才的 AccessKey ID
2、secret-key:页面点击‘查看 Secret’就能看的到了
3、bucket:新建的桶的名称oss-test
4、endpoint:页面截图,选择自己的桶就能看到对应的endpoint

2 : 代码配置

2.1、说明

本篇代码,主要做的两件事:
1、文件上传至OSS
2、对服务器磁盘文件转存至OSS

2.2、配置文件

在application.yml中增加配置

#阿里云oss
alibaba:
  cloud:
    access-key: **********
    secret-key: **********
    oss:
      endpoint: oss********.aliyuncs.com
      bucket: *******
  config:
    # oss开关 0:关  1:开
    oss-switch: 1
    # oss 开始使用时间
    oss-date: 2022-01-01
    # oss 文件夹目录
    oss-directory: image,attach,video,audio,template
    # oss title
    oss-title: https://
	# oss business directory
    business-directory: user,org

非常非常重要在配置的时候上面4个重要参数的位置,以及名称一定不能修改,否则会报找不到endPoint的错

2.3、加载配置文件代码

新建 YmlConfigBean.java

package com.upload.bean;

import org.springframework.stereotype.Component;
import java.util.List;

/**
 * 配置文件参数读取
 */
@Component
public class YmlConfigBean {
	
    // 阿里云OSS 申请的 key id
    public volatile static String OSS_KEY_ID;
    // 阿里云OSS 申请的 key secret
    public volatile static String OSS_KEY_SECRET;
    // 阿里云OSS endpoint
    public volatile static String OSS_ENDPOINT;
    // 阿里云OSS bucket
    public volatile static String OSS_BUCKET;
    // 阿里云OSS 开关 0 关 1 开
    public volatile static String OSS_SWITCH;
    // 阿里云OSS 开始使用时间
    public volatile static String OSS_DATE;
    // 阿里云OSS 文件夹目录
    public volatile static List<String> OSS_DIRECTORY;
    // 阿里云OSS 开始使用时间
    public volatile static String OSS_TITLE;
	//业务文件类别
    public volatile static List<String> BUSINESS_DIRECTORY;
}

新建 YmlConfigBeanMethod.java

package com.upload.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.List;

@Component
public class YmlConfigBeanMethod {

    @Value("#{'${alibaba.cloud.access-key}'}")
    private void setOssKeyId(String key) {
        YmlConfigBean.OSS_KEY_ID = key;
    }
    @Value("#{'${alibaba.cloud.secret-key}'}")
    private void setOssKeySecret(String key) {
        YmlConfigBean.OSS_KEY_SECRET = key;
    }
    @Value("#{'${alibaba.cloud.oss.endpoint}'}")
    private void setOssEndpoint(String key) {
        YmlConfigBean.OSS_ENDPOINT = key;
    }
    @Value("#{'${alibaba.cloud.oss.bucket}'}")
    private void setOssBucket(String key) {
        YmlConfigBean.OSS_BUCKET = key;
    }
    @Value("#{'${alibaba.config.oss-switch}'}")
    private void setOssSwitch(String key) {
        YmlConfigBean.OSS_SWITCH = key;
    }
    @Value("#{'${alibaba.config.oss-date}'}")
    private void setOssDate(String key) {
        YmlConfigBean.OSS_DATE = key;
    }
    @Value("#{'${alibaba.config.oss-directory}'.split(',')}")
    public void setOssDirectory(List<String> key){
        YmlConfigBean.OSS_DIRECTORY = key;
    }
    @Value("#{'${alibaba.config.oss-title}'}")
    private void setOssTitle(String key) {
        YmlConfigBean.OSS_TITLE = key;
    }

	@Value("#{'${alibaba.config.business-directory}'.split(',')}")
    public void setBusinessDirectory(List<String> key){
        YmlConfigBean.BUSINESS_DIRECTORY= key;
    }
    
}

2.4、封装统一的DTO

建一个统一的DTO Result.java

package com.upload.bean;

/**
 * 统一的DTO
 */
public class Result<T> {
    private boolean success = true;
    private Integer code = 0;
    private String msg;
    private T data;

    public boolean isSuccess() {
        return this.code == 0;
    }
    public void setSuccess(boolean success) {
        this.success = success;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
        if(code != 0){
            success = false;
        }
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }

    public Result() {
        super();
    }
    public Result(boolean success) {
        this.success = success;
        if(success){
            code = 0;
        }
    }
    public Result(int code) {
        super();
        success = false;
        this.code = code;
    }
    public Result(String msg) {
        success = false;
        this.msg = msg;
    }
    public Result(boolean success, String msg) {
        super();
        this.success = success;
        this.msg = msg;
    }
    public Result(int code, String msg) {
        super();
        success = false;
        this.code = code;
        this.msg = msg;
    }

    /*设置返回为成功*/
    public static Result ok() {
        return new Result();
    }
    /*设置返回为成功,同时设置返回数据*/
    public Result<T> ok(T data) {
        Result<T> result = new Result<T>();
        result.setData(data);
        return result;
    }
    /*设置返回为失败,默认未知异常*/
    public static Result error() {
        return error(500, "未知异常,请联系管理员!");
    }
    /*设置返回为失败,同时设置异常信息*/
    public static Result error(String msg) {
        return error(500, msg);
    }
    /*设置返回为失败,同时设置code,msg*/
    public static Result error(Integer code,String msg) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
    public static Result<Object> error(Integer code,String msg,Object data) {
        Result<Object> result = new Result<Object>();
        result.setData(data);
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
    public static Result success(Object data) {
        Result<Object> result = new Result<Object>();
        result.setData(data);
        return result;
    }
    public static Result success(String msg) {
        Result result = new Result();
        result.setMsg(msg);
        return result;
    }

}

常量配置好之后,方便后续直接使用配置文件的中内容。

2.5、OSS上传Controller

新建 OssUploadController.java

package com.upload;

import com.upload.service.IOssUploadService;
import com.upload.bean.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 

* 阿里云OSS 前端控制器 *

*/
@Controller public class OssUploadController { @Resource private IOssUploadService ossUploadService; /** * OSS文件上传 */ @RequestMapping("/uploadOss") @ResponseBody public Result upload(@RequestParam String ossDirectory, @RequestParam String businessDirectory, @RequestParam MultipartFile file, HttpServletRequest request) { return ossUploadService.upload(ossDirectory, businessDirectory, file, request); } /** * OSS文件迁移 */ @RequestMapping("/migrationOss") @ResponseBody public Result doDataMigration(@RequestParam String ossDirectory, @RequestParam String businessDirectory) { return ossUploadService.doDataMigration(ossDirectory, businessDirectory, true); } }

2.6、OSS上传Service

新建 IOssUploadService.java

package com.upload.service;

import com.upload.bean.Result;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;

/**
 * 

* 阿里云OSS 服务类 */ public interface IOssUploadService { Result upload(String ossDirectory, String businessDirectory, MultipartFile file, HttpServletRequest request); Result doDataMigration(String ossDirectory, String businessDirectory, boolean threadFlag); }

2.7、OSS上传ServiceImpl

新建 OssUploadServiceImpl.java

package com.upload.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.CannedAccessControlList;
import com.upload.bean.Result;
import com.upload.bean.YmlConfigBean;
import com.upload.entity.FileUpload;
import com.upload.service.IOssUploadService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class OssUploadServiceImpl implements IOssUploadService {

//    @Resource
//    private UploadMapper uploadMapper;
    private final static String ROOT_PATH = "/data/file/";

    /**
     * 对外提供的文件上传
     * @param ossDirectory OSS所属模块
     * @param fileDir 文件所属模块
     * @param file 文件
     * @param request 请求
     */
    @Override
    public Result upload(String ossDirectory, String fileDir, MultipartFile file, HttpServletRequest request) {
        if (file.isEmpty()) {
            return Result.error("不能上传空文件");
        }
        String originalFilename = file.getOriginalFilename();
        Long fileBytes = file.getSize();
        if (Strings.isBlank(originalFilename) || 0L == fileBytes) {
            return Result.error("不能上传空文件");
        }
        if(Strings.isBlank(ossDirectory)){
            ossDirectory = "image";
        } else {
            if (!YmlConfigBean.OSS_DIRECTORY.contains(ossDirectory.startsWith("/") ? ossDirectory.substring(1) : ossDirectory)) {
                log.info("文件上传目录非法,非法目录:"+ ossDirectory);
                return Result.error("文件上传目录非法,请更改文件上传目录");
            }
        }
        if (!YmlConfigBean.BUSINESS_DIRECTORY.contains(fileDir.startsWith("/") ? fileDir.substring(1) : fileDir)) {
            log.info("文件上传目录非法,非法目录:"+ fileDir);
            return Result.error("文件上传目录非法,请更改文件上传目录");
        }
        String fileMd5;
        try {
            fileMd5 = DigestUtils.sha256Hex(file.getInputStream());
        } catch (Exception e) {
            log.error(file.getOriginalFilename() + "验证文件md5失败",e);
            return Result.error("当前验证文件md5失败");
        }
        Result<String> result = new Result<>();
        String uploadUrl = null;
        String newName = null;
        OSS ossClient = getOSSClient();
        try {
            //获取上传文件流
            InputStream inputStream = file.getInputStream();
            //构建日期路径:/2019/02/26/文件名
            String fileType = originalFilename.split("\\.")[originalFilename.split("\\.").length - 1];
            newName = DateFormatUtils.format(new Date(), "yyMMddHHmmss") +
                    (new SecureRandom().nextInt(100) + 100) + "." + fileType;
            String newFileDir = (fileDir.startsWith("/") ? fileDir.substring(1) : fileDir).trim().replace(" ","") +
                    getDatePath();
            String fileUrl = ossDirectory + "/" + newFileDir + newName;
            // 上传文件 (上传文件流的形式)
            ossClient.putObject(YmlConfigBean.OSS_BUCKET, fileUrl, inputStream);
            //获取url地址
            uploadUrl = YmlConfigBean.OSS_TITLE + YmlConfigBean.OSS_BUCKET + "." + YmlConfigBean.OSS_ENDPOINT + "/" + fileUrl;
        } catch (IOException e) {
            log.error("上传OSS失败,文件名:" + originalFilename);
            throw new RuntimeException("上传OSS失败");
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        //文件上传实体属性赋值,数据入库
        try {
            log.info("原文件名称:" + originalFilename + "\n" + "文件MD5码:" + fileMd5 + "\n" + "新文件名称:" + newName + "\n" +
            "文件路径:" + uploadUrl + "\n" + "文件大小:" + fileBytes);
//            uploadMapper.doUploadInsert(null);
        } catch (Exception e) {
            log.error("上传文件,数据库记录失败", e);
        }
        result.setData(uploadUrl);
        return result;
    }

    /**
     * 文件迁移
     * @param ossDirectory 需要同步的OSS文件夹
     * @param businessDirectory 业务文件路径,以此查询表中数据
     * @param threadFlag 是否开启异步线程
     * @return Result
     */
    @Override
    public Result doDataMigration(String ossDirectory, String businessDirectory, boolean threadFlag){
        if(Strings.isBlank(businessDirectory)) return Result.error("路径不能为空");
//        List fileUploads = uploadMapper.selectList();
        List<FileUpload> fileUploads = new ArrayList<>();
        if(null == fileUploads || fileUploads.size() == 0) return Result.error("暂无数据");
        if(threadFlag){
            Thread thread = new Thread(()->{
                doSonThread(fileUploads, ossDirectory);
            });
            thread.start();
        } else {
            doSonThread(fileUploads, ossDirectory);
        }
        return Result.success("文件迁移中,请稍后查看!");
    }

    private void doSonThread(List<FileUpload> fileUploads, String ossDirectory){
        if(Strings.isBlank(ossDirectory)) {
            ossDirectory = "image";
        }
        String filePath = null;
        for(FileUpload fileUpload : fileUploads){
            if(Strings.isBlank(fileUpload.getFilePath()) || Strings.isBlank(fileUpload.getFileName())){
                continue;
            }
            filePath = uploadFileAndDeleteByPath(ROOT_PATH + fileUpload.getFilePath(), fileUpload.getFileName(), ossDirectory);
            //更新新的路径入库
            fileUpload.setFilePathNew(filePath);
//            uploadMapper.doUploadUpdate(fileUpload);
        }
    }

    public static String uploadFileAndDeleteByPath(String path, String fileName, String ossDirectory) {
        File file = new File(path + File.separator + fileName);
        return uploadFileAndDeleteByFile(file, ossDirectory);
    }

    public static String uploadFileAndDeleteByFile(File file, String ossDirectory) {
        if (file.isDirectory()) return null;
        String filePath = null;
        Boolean deleteFlag = false;
        try {
            filePath = uploadHistory(ossDirectory, file.getPath(), file);
            deleteFlag = checkExists(filePath.substring(filePath.indexOf(YmlConfigBean.OSS_ENDPOINT) + 1 + YmlConfigBean.OSS_ENDPOINT.length(), filePath.length()));
        } catch (IOException e) {
            log.error("上传OSS失败,文件名:" + file.getName());
            throw new RuntimeException("上传OSS失败");
        }
        if(deleteFlag){
            file.delete();
        }
        return filePath;
    }

    public static String uploadHistory(String ossDirectory, String businessDirectory, File file) throws IOException{
        String filename = file.getName();
        OSS ossClient = getOSSClient();
        //获取上传文件流
        InputStream inputStream = new FileInputStream(file);
        //构建日期路径:/2019/02/26/文件名
        String fileType = filename.split("\\.")[filename.split("\\.").length - 1];
        String newName = filename.substring(0, filename.indexOf(".")) + "_" + (new SecureRandom().nextInt(1000) + 1000) + "." + fileType;
        String newFileDir = (businessDirectory.startsWith("/") ? businessDirectory.substring(1) : businessDirectory).trim().replace(" ","");
        String fileUrl = ossDirectory + "/" + newFileDir + newName;
        // 上传文件 (上传文件流的形式)
        ossClient.putObject(YmlConfigBean.OSS_BUCKET, fileUrl, inputStream);
        ossClient.shutdown();
        //获取url地址
        return YmlConfigBean.OSS_TITLE + YmlConfigBean.OSS_BUCKET + "." + YmlConfigBean.OSS_ENDPOINT + "/" + fileUrl;
    }

    public static boolean checkExists(String objectName) throws IOException{
        OSS ossClient = getOSSClient();
        Boolean flag = ossClient.doesObjectExist(YmlConfigBean.OSS_BUCKET, objectName);
        ossClient.shutdown();
        return flag;
    }

    public static OSS getOSSClient() {
        OSS ossClient = new OSSClientBuilder().build(YmlConfigBean.OSS_ENDPOINT, YmlConfigBean.OSS_KEY_ID, YmlConfigBean.OSS_KEY_SECRET);
        //判断oss实例是否存在:如果不存在则创建,如果存在则获取
        if (!ossClient.doesBucketExist(YmlConfigBean.OSS_BUCKET)) {
            //创建bucket
            ossClient.createBucket(YmlConfigBean.OSS_BUCKET);
            //设置oss实例的访问权限:公共读
            ossClient.setBucketAcl(YmlConfigBean.OSS_BUCKET, CannedAccessControlList.PublicRead);
        }
        return ossClient;
    }

    /*public static void uploadFileAndDelete(File file) {
        if (file.isDirectory()) {
            String[] fileList = file.list();
            if(null != fileList && fileList.length > 0){
                //递归删除目录中的子目录下
                File subFile = null;
                for(String str : fileList){
                    subFile = new File(file, str);
                    log.info(subFile.getPath());
                    uploadFileAndDelete(subFile);
                }
            }
        }
        uploadFileAndDeleteByFile(file, null);
    }*/

    public static String getDatePath(){
        return "/" + DateFormatUtils.format(new Date(), "yyyy-MM-dd").replaceAll("-","/") + "/";
    }

}

3 : 测试

3.1、文件上传

JAVA集成阿里云OSS对象存储_第4张图片
JAVA集成阿里云OSS对象存储_第5张图片

在这里插入图片描述
在OSS上存储的路径为:OSS文件夹(image)+ 业务自定义文件夹名称(org)+ 年月日时间路径 + 重命名文件名称。

3.2、文件迁移

大致思路:
1、根据业务需要,查询数据库中的文件路径及名称,到服务器磁盘中查找该文件。
2、调用简易版的文件上传,上传至OSS中。
3、上传之后回调阿里自带方法doesObjectExist进行回溯校验,检查是否在OSS中存在。
4、如存在该文件,则删除服务器磁盘对应的文件即可。

因代码需根据业务数据来进行数据的查询等操作,可自行修改并验证。

4 : 总结

4.1、参考资料

参考资料:异常官网链接:https://help.aliyun.com/document_detail/32023.html

4.2、注意事项

注意事项在配置的时候上面4个重要参数的位置,以及名称一定不能修改,否则会报找不到endPoint的错

4.3、源码链接

CSDN资源链接:https://download.csdn.net/download/qq_38254635/87352781
百度网盘资源链接:https://pan.baidu.com/s/1kl6KIntr1qvcJPG642DWAA?pwd=fsj2
提取码: fsj2

有什么不对的还望指正,书写不易,觉得有帮助就点个赞吧!

你可能感兴趣的:(项目demo,java,阿里云,服务器,OSS对象存储)