美文网首页Java 杂谈spring boot
Springboot 迁移及上传文件至阿里云OSS

Springboot 迁移及上传文件至阿里云OSS

作者: f2a928cacb8d | 来源:发表于2018-09-27 15:44 被阅读2次

    摘要:

    本文介绍GitClub小程序后端的服务器文件的迁移以及更新图片上传至阿里云OSS存储服务器,如果不了解GitClub小程序的朋友可以看下我的上篇文章关于Android开源库分享平台,(GitClub)微信小程序的开发体验,在此特别纠正下,当前版本暂时只有Android的开源库分享,后续会增加Java、iOS、前端等不同语言的分类,感兴趣的可以去关注下我们的小程序,源码地址:GitClub。铺垫结束,请使用扫描这个二维码登陆GitClub小程序参观。

    Geek Reader小程序二维码

    一、导入依赖包,在pox.xml中加入

    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
        <version>2.8.3</version>
    </dependency>
    

    二、配置OSS的参数,创建类OSSConfig

    1、添加oss.properties配置文件,内容如下:
    #阿里云OSS配置
    #原服务器地址
    bucketUrl = https://bucketName.oss-cn-shenzhen.aliyuncs.com
    #自定义解析后服务器地址
    baseUrl = https://xxx.502tech.com
    #可以选择其他的地址
    endpoint = https://oss-cn-qingdao.aliyuncs.com
    #已经在控制台创建的bucket
    bucketName = bucketName
    #你上传文件的保存路径,如果bucket中不存在则创建(其实原理并不是文件夹,只是文件名,详情请先阅读官方文档)
    picLocation = GitClub/image/
    #相应的id和key值,请填写你具体的值,这里不方便展示我自己的。
    accessKeyId = 阿里云OSS的accessKeyId
    accessKeySecret = 阿里云OSS的accessKeySecret
    
    2、创建类OSSConfig
    public class OSSConfig {
    
        private  String bucketUrl;          //原图片服务器地址
        private  String baseUrl;        //自定义解析后的图片服务器地址
        private  String endpoint;       //连接区域地址
        private  String accessKeyId;    //连接keyId
        private  String accessKeySecret;    //连接秘钥
        private  String bucketName;     //需要存储的bucketName
        private  String picLocation;    //图片保存路径
    
        public OSSConfig() {
            try {
                this.bucketUrl = SystemConfig.getConfigResource("bucketUrl");
                this.baseUrl = SystemConfig.getConfigResource("baseUrl");
                this.endpoint = SystemConfig.getConfigResource("endpoint");
                this.bucketName = SystemConfig.getConfigResource("bucketName");
                this.picLocation = SystemConfig.getConfigResource("picLocation");
                this.accessKeyId = SystemConfig.getConfigResource("accessKeyId");
                this.accessKeySecret = SystemConfig.getConfigResource("accessKeySecret");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        ...
        省略get、set方法
    

    三、创建OSS工具类OSSUploadUtil

    private static OSSConfig config = null;
    
        /**
         *
         * @MethodName: uploadFile
         * @Description: OSS单文件上传
         * @param file
         * @param fileType 文件后缀
         * @return String 文件地址
         */
        public static String uploadFile(File file,String fileType){
            config = config == null ? new OSSConfig():config;
            //通过UUID生成文件名
            String fileName = config.getPicLocation()
                    +UUID.randomUUID().toString().toUpperCase()
                    .replace("-", "")
                    +"."+fileType;
            return putFile(file,fileType,fileName);
        }
    
        /**
         *
         * @MethodName: updateFile
         * @Description: 更新文件:只更新内容,不更新文件名和文件地址。
         *      (因为地址没变,可能存在浏览器原数据缓存,不能及时加载新数据,例如图片更新,请注意)
         * @param file
         * @param fileType
         * @param oldUrl
         * @return String
         */
        public static String updateFile(File file,String fileType,String oldUrl){
            String fileName = getFileName(oldUrl);
            if(fileName==null) return null;
            return putFile(file,fileType,fileName);
        }
    
        /**
         *
         * @MethodName: replaceFile
         * @Description: 替换文件:删除原文件并上传新文件,文件名和地址同时替换
         *      解决原数据缓存问题,只要更新了地址,就能重新加载数据)
         * @param file
         * @param fileType 文件后缀
         * @param oldUrl 需要删除的文件地址
         * @return String 文件地址
         */
        public static String replaceFile(File file,String fileType,String oldUrl){
            boolean flag = deleteFile(oldUrl);      //先删除原文件
            if(!flag){
                //更改文件的过期时间,让他到期自动删除。
            }
            return uploadFile(file, fileType);
        }
    
        /**
         *
         * @MethodName: deleteFile
         * @Description: 单文件删除
         * @param fileUrl 需要删除的文件url
         * @return boolean 是否删除成功
         */
        public static boolean deleteFile(String fileUrl){
            config = config == null ? new OSSConfig():config;
    
            String bucketName = OSSUploadUtil.getBucketName(fileUrl);       //根据url获取bucketName
            String fileName = OSSUploadUtil.getFileName(fileUrl);           //根据url获取fileName
            if(bucketName==null||fileName==null) return false;
            OSSClient ossClient = null;
            try {
                ossClient = new OSSClient(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret());
                GenericRequest request = new DeleteObjectsRequest(bucketName).withKey(fileName);
                ossClient.deleteObject(request);
            } catch (Exception oe) {
                oe.printStackTrace();
                return false;
            } finally {
                ossClient.shutdown();
            }
            return true;
        }
    
        /**
         *
         * @MethodName: batchDeleteFiles
         * @Description: 批量文件删除(较快):适用于相同endPoint和BucketName
         * @param fileUrls 需要删除的文件url集合
         * @return int 成功删除的个数
         */
        public static int deleteFile(List<String> fileUrls){
            int deleteCount = 0;    //成功删除的个数
            String bucketName = OSSUploadUtil.getBucketName(fileUrls.get(0));       //根据url获取bucketName
            List<String> fileNames = OSSUploadUtil.getFileName(fileUrls);           //根据url获取fileName
            if(bucketName==null||fileNames.size()<=0) return 0;
            OSSClient ossClient = null;
            try {
                ossClient = new OSSClient(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret());
                DeleteObjectsRequest request = new DeleteObjectsRequest(bucketName).withKeys(fileNames);
                DeleteObjectsResult result = ossClient.deleteObjects(request);
                deleteCount = result.getDeletedObjects().size();
            } catch (OSSException oe) {
                oe.printStackTrace();
                throw new RuntimeException("OSS服务异常:", oe);
            } catch (ClientException ce) {
                ce.printStackTrace();
                throw new RuntimeException("OSS客户端异常:", ce);
            } finally {
                ossClient.shutdown();
            }
            return deleteCount;
    
        }
    
        /**
         *
         * @MethodName: batchDeleteFiles
         * @Description: 批量文件删除(较慢):适用于不同endPoint和BucketName
         * @param fileUrls 需要删除的文件url集合
         * @return int 成功删除的个数
         */
        public static int deleteFiles(List<String> fileUrls){
            int count = 0;
            for (String url : fileUrls) {
                if(deleteFile(url)){
                    count++;
                }
            }
            return count;
        }
    
        /**
         *
         * @MethodName: putFile
         * @Description: 上传文件
         * @param file
         * @param fileType
         * @param fileName
         * @return String
         */
        private static String putFile(File file, String fileType, String fileName){
            config = config==null?new OSSConfig():config;
            String url = null;      //默认null
            OSSClient ossClient = null;
            try {
                ossClient = new OSSClient(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret());
                InputStream input = new FileInputStream(file);
                ObjectMetadata meta = new ObjectMetadata();             // 创建上传Object的Metadata
                meta.setContentType(OSSUploadUtil.contentType(fileType));       // 设置上传内容类型
                meta.setCacheControl("no-cache");                   // 被下载时网页的缓存行为
                PutObjectRequest request = new PutObjectRequest(config.getBucketName(), fileName,input,meta);           //创建上传请求
                ossClient.putObject(request);
                Date expiration = new Date(new Date().getTime() + 3600L * 1000 * 24 * 365 * 10); // 设置URL过期时间为10年  3600L* 1000*24*365*10
                //上传成功再返回的文件路径
                url = ossClient.generatePresignedUrl(config.getBucketName(), fileName, expiration)
                                                    .toString()
                                                    .replaceFirst(config.getBucketUrl(), config.getBaseUrl());
            } catch (OSSException | FileNotFoundException | ClientException oe) {
                oe.printStackTrace();
                return null;
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
            return url;
        }
    
        /**
         *
         * @MethodName: contentType
         * @Description: 获取文件类型
         * @param fileType
         * @return String
         */
        private static String contentType(String fileType){
            fileType = fileType.toLowerCase();
            String contentType = "";
            switch (fileType) {
                case "bmp": contentType = "image/bmp";
                    break;
                case "gif": contentType = "image/gif";
                    break;
                case "png":
                case "jpeg":
                case "jpg": contentType = "image/jpeg";
                    break;
                case "html":contentType = "text/html";
                    break;
                case "txt": contentType = "text/plain";
                    break;
                case "vsd": contentType = "application/vnd.visio";
                    break;
                case "ppt":
                case "pptx":contentType = "application/vnd.ms-powerpoint";
                    break;
                case "doc":
                case "docx":contentType = "application/msword";
                    break;
                case "xml":contentType = "text/xml";
                    break;
                case "mp4":contentType = "video/mp4";
                    break;
                default: contentType = "application/octet-stream";
                    break;
            }
            return contentType;
        }
    
        /**
         *
         * @MethodName: getBucketName
         * @Description: 根据url获取bucketName
         * @param fileUrl 文件url
         * @return String bucketName
         */
        private static String getBucketName(String fileUrl){
            String http = "http://";
            String https = "https://";
            int httpIndex = fileUrl.indexOf(http);
            int httpsIndex = fileUrl.indexOf(https);
            int startIndex  = 0;
            if(httpIndex==-1){
                if(httpsIndex==-1){
                    return null;
                }else{
                    startIndex = httpsIndex+https.length();
                }
            }else{
                startIndex = httpIndex+http.length();
            }
            int endIndex = fileUrl.indexOf(".oss-");
            return fileUrl.substring(startIndex, endIndex);
        }
    
        /**
         *
         * @MethodName: getFileName
         * @Description: 根据url获取fileName
         * @param fileUrl 文件url
         * @return String fileName
         */
        private static String getFileName(String fileUrl){
            String str = "aliyuncs.com/";
            int beginIndex = fileUrl.indexOf(str);
            if(beginIndex==-1) return null;
            return fileUrl.substring(beginIndex+str.length());
        }
    
        /**
         *
         * @MethodName: getFileName
         * @Description: 根据url获取fileNames集合
         * @param fileUrls 文件url
         * @return List<String>  fileName集合
         */
        private static List<String> getFileName(List<String> fileUrls){
            List<String> names = new ArrayList<>();
            for (String url : fileUrls) {
                names.add(getFileName(url));
            }
            return names;
        }
    
    }
    

    四、测试

    //把之前上传到项目特定目录下的逻辑修改成上传至OSS
    @PostMapping("/uploadArticleImg")
        public Result<Map<String, String>> uploadArticleImg(@RequestParam(value = "article_img") MultipartFile file) {
            if (file == null || file.isEmpty() || file.getSize() == 0) {
                return ResultUtils.error(ResultCode.UPLOAD_FILE_EMPTY);
            }
            if (file.getSize() > 10 * 1024 * 1024) {
                return ResultUtils.error(ResultCode.UPLOAD_FILE_LIMIT);
            }
            Map<String, String> map = new HashMap<>();
            String fileType = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")+1);
            //OSS单文件上传,返回上传成功后的oss存储服务器中的url
            String fileName = OSSUploadUtil.uploadFile(FileUtils.multi2File(file), fileType);
            map.put(file.getName(), fileName);
            return ResultUtils.ok(map);
        }
    

    五、如何把数据库中把之前已经上传的文件URL更新成OSS返回的URL

    @PostMapping("/trasform2OSS")
        public Result<Boolean> trasformImg2OSS(){
            File path = null;
            try {
                path = new File(ResourceUtils.getURL("classpath:").getPath());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            if (!path.exists()) path = new File("");
            System.out.println("path:" + path.getAbsolutePath());
            //如果上传目录为/static/images/upload/,则可以如下获取:
            File upload = new File(path.getAbsolutePath(), "static/images/upload/");
            if (!upload.exists()) upload.mkdirs();
            System.out.println("upload url:" + upload.getAbsolutePath());
            File[] files = upload.listFiles();
    
            //更新图片的url到oss  并把最新oss的图片地址保存到数据库
            List<Article> articles = articleRepository.findAll();
            articles.forEach(article -> {
                if (null != article){
                    for (File file : files){
                        if(null != file){
                            if(null == article.getImg_url() || null == file.getName()){
                                continue;
                            }
                            if(article.getImg_url().contains(file.getName())){
                                //上传到oss
                                String fileType = file.getName().substring(file.getName().lastIndexOf(".")+1);
                                String url = OSSUploadUtil.uploadFile(file, fileType);
                                logger.info("上传到oss地址:"+url);
                                //更新到服务器
                                article.setImg_url(url);
                                articleRepository.saveAndFlush(article);
                                //更新数据到引擎
                                articleSearchRepository.save(new ESArticle(article));
                            }
                        }
                    }
                }
            });
            return ResultUtils.ok(true);
        }
    

    六、阿里云OSS管理配置的一些坑

    因为之前我们的图片上传至项目目录中的指定路径如:https://502tech.com/geekdaily/xxx/xxx/123.png, 现在需要全部替换成如:https://xxx.502tech.com/123.png
    格式,注意:这里xxx.502tech.com是我们的二级域名,上传文件至OSS之后默认会返回如:https://bucketName.oss-cn-shenzhen.aliyuncs.com/123.png 格式。需要我们手动在阿里云OSS域名管理中去绑定域名,如果想要使用https,则需要申请SSL证书,这里你可以申请一个免费的,可以自行百度,大概15分钟会申请成功,然后需要在OSS的域名管理中添加SSL证书,这里切记:下载nginx版本的证书,然后复制粘贴对应的公钥和私钥。

    相关文章

      网友评论

        本文标题:Springboot 迁移及上传文件至阿里云OSS

        本文链接:https://www.haomeiwen.com/subject/rjieoftx.html