前端 vue + vant - 后端 java - 阿里云OSS存储 实现文件上传

前言

        不知道大家有没有过这样一个开发经历,用户可以从前端上传自己的头像,头像上传到服务器后保存到数据库,然后在前端显示头像。在我还没有意识到前端显示图片需要图片的URL地址时,我完成了前端选择头像上传,然后后端保存图片,将图片名直接返回给前端,希望前端能够展示头像。但是,我折腾了好久才发现,想要展示图片,需要服务器的加入。首先,需要获取到前端传过来的文件(图片或者其他文件),然后将其保存到服务器(或者专门用于存储文件的存储云服务),保存到服务器后,会返回一个URL地址,然后将该URL地址保存到数据库中,返回给前端,前端就可以展示头像。

        所以,这里要有一个观念的转换,图片是保存到服务器中的,而不是保存到数据库中的,数据库中只是保存了图片地址而已。

ps:前端上传文件可进入传送门:前端 vue + vant 实现文件上传-CSDN博客

OSS云存储服务

这里重点介绍用法

官网:

什么是对象存储OSS_对象存储(OSS)-阿里云帮助中心 (aliyun.com)icon-default.png?t=N7T8https://help.aliyun.com/zh/oss/product-overview/what-is-oss?spm=a2c4g.11186623.0.0.3bb61860yLKtGL

介绍

阿里云对象存储OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务,可提供99.9999999999%(12个9)的数据持久性,99.995%的数据可用性。多种存储类型供选择,全面优化存储成本。

使用

前提条件

需要java环境在1.7.0版本以上,查看java版本命令

java -version

下载SDK

地址:https://github.com/aliyun/aliyun-oss-java-sdk/releases

建议下载最新版本SDK,下载到本地即可

安装依赖

如果你的项目是Maven项目直接将上一步下载的SDK中的pom.xml文件中的maven地址拷贝到自己的项目中即可

下图是我下载的SDK版本中的部分pom.xml文件,只需要将红框中的内部拷贝到自己的项目中即可

另外。对于java9以上的版本,还需要添加JAXB相关依赖如下:

<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>
<!-- no more than 2.3.3-->
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.3</version>
</dependency>

配置访问凭证

有两种访问凭证,一种是临时的,一种是长久的,如果对于安全性要求较高,那么就选择临时的,如果对于安全性要求不高,那么可以选择长期的,这里我选择的是长期的凭证(windows,其他操作系统可以参照上面给出的官方地址)

步骤如下:

获取RAM用户的访问密钥

什么是RAM用户?看文档去吧:什么是RAM用户_访问控制(RAM)-阿里云帮助中心,使用OSS的前提是你已经有了阿里云账号,并且已经创建了RAM用户,如果你还没有前置操作,可以跟着文档去操作,花个半小时左右就搞定。

这一步需要使用到的密钥就是你创建好RAM用户后平台自动给你生成的,访问密钥AccessKey(简称AK)是阿里云提供给阿里云用户的永久访问密钥,用于通过开发工具(API、CLI、SDK、Cloud Shell、Terraform等)访问阿里云时的身份验证,不用于控制台登录。AccessKey包括AccessKey ID和AccessKey Secret,需要一起使用,需要妥善保管

配置访问密钥

获取到自己的访问密钥后,接下来就需要配置访问密钥了

1. 首先配置环境变量

在命令行窗口中输入以下命令:

set OSS_ACCESS_KEY_ID=LTAI4GDty8ab9W4Y1D**** // 你的appid
set OSS_ACCESS_KEY_SECRET=IrVTNZNy5yQelTETg0cZML3TQn****  // 你的appsecret

执行以下命令使更改生效

setx OSS_ACCESS_KEY_ID "%OSS_ACCESS_KEY_ID%"
setx OSS_ACCESS_KEY_SECRET "%OSS_ACCESS_KEY_SECRET%"

执行命令验证环境变量配置

echo %OSS_ACCESS_KEY_ID%
echo %OSS_ACCESS_KEY_SECRET%

如果配置成功,则返回如下:

LTAI4GDty8ab9W4Y1D****
IrVTNZNy5yQelTETg0cZML3TQn**** 

注意:这里可能会遇到小坑,以上命令执行完之后,建议重新启动电脑,以确保配置生效,否则后端运行时可能会报类似于密钥为空之类的错

2.  然后就是在代码中从环境变脸中获取到你的密钥(这行代码在后续代码还会讲到,这里先不用管)

// 使用环境变量中获取的RAM用户的访问密钥配置访问凭证。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();

编写工具类

这部分就是无脑复制粘贴,以下代码是上传文件(图片)用的,可以直接赋值粘贴到你的项目中,然后就可以使用

package com.hitsz.badboyHelm.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.UUID;

@Component
public class OSSutils {

    // 访问域名,参照官方地址:https://help.aliyun.com/zh/oss/user-guide/regions-and-endpoints?spm=a2c4g.11186623.0.i1#concept-zt4-cvy-5db
    @Value("${aliyun-oss.endpoint}")
    private String endpoint;

    // 存储空间名称,在OSS的控制台上创建存储空间时会得到。官方地址:https://oss.console.aliyun.com/bucket
    @Value("${aliyun-oss.bucketName}")
    private String bucketName;

    public String uploadFileToOSS(MultipartFile file) throws Exception{
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();

        // 获取上传文件的输入流
        InputStream inputStream = file.getInputStream();

        // 使用UUID通用唯一识别码 + 后缀名的形式,方式文件名重复导致覆盖
        String orignalFilename = file.getOriginalFilename();
        // 增加断言null值抛出异常
        assert orignalFilename != null;
        String fileName = UUID.randomUUID().toString() + orignalFilename.substring(orignalFilename.lastIndexOf("."));

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
        // 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
        String objectName = fileName;

        // 文件上传到服务器之后的文件访问路径
        String url = "";
        try {
            ossClient.putObject(bucketName, objectName, inputStream);

            //拼接文件访问路径并返回  在endpoint名称中加入bucket名称 最后拼接上文件名
            url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("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.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return url;
    }
}

注意:代码中的url就是图片保存到阿里云存储服务中后返回的地址,需要将这个url地址保存到数据库中

代码中,enpoint,backetName 是需要配置在配置文件中的(也可以直接写在代码中,只是违背了开闭原则,因为以后如果需要修改这两个信息,就必须要修改代码,如果写在配置文件中,就不需要修改代码),如下:

#OSS配置
aliyun-oss:
  endpoint: https://oss-cn-shenzhen.aliyuncs.com
  bucketName: badboy-helm-img

对enpoint 和 backetName 不熟悉的也可以去看文档,

enpoint :访问域名和数据中心_对象存储(OSS)-阿里云帮助中心

backetName:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台

实操

配置好之后,就可以对前端传过来的文件进行上传了,示例代码如下(service层):

@Autowired
private OSSutils osSutils;

@PostMapping("/handleUpdataAvatar")
public BaseResponse<User> updateUserAvatarById(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception{

    // 调用封装的OSS工具类将文件上传到OSS
    String url = osSutils.uploadFileToOSS(file);
    // 获取当前用户
    User loginUser = userService.getLoginUser(request);
    // 更新用户头像
    loginUser.setUserAvatar(url);
    boolean result = userService.updateById(loginUser);
    // 将更新完的用户信息返回
    User user = userService.getById(loginUser.getId());
    // 对用户信息进行脱敏然后返回
    return ResultUtils.success(userService.getSafetyUser(user));
}

扩展

如果需要接受前端传过来的多个键值对组成的formData对象(表单数据),接受时,只需要创建一个bean对象,bean对象中的字段与前端传过来的键值对中的键一一对应即可,示例代码如下:

javaBean对象

// 字段名与前端传过来的字段名一致
@Data
public class AddRoleRequest implements Serializable {

    /**
     *  角色真名
     */
    private String roleName;

    /**
     *  角色昵称
     */
    private String roleNickName;

    /**
     *  角色简介
     */
    private String roleProfile;

    /**
     *  角色头像,类型为MultipartFile,因为前端是以表单数据形式传递过来的
     */
    private MultipartFile roleAvatar;

    /**
     *  角色标签
     */
    private List<String> tags;

}

controller层:

@PostMapping("/add")
public BaseResponse<Role> addRole2(AddRoleRequest addRoleRequest, HttpServletRequest request){
    if(addRoleRequest == null){
        throw new BusinessException(ErrorCode.OPERATION_ERROR);
    }
    // 获取当前用户
    User loginUser = userService.getLoginUser(request);
    Role role = roleService.addRole(addRoleRequest, loginUser);
    return ResultUtils.success(role);
}

需要注意的是:请求方式必须是post,并且不能使用@RequestBody来接收参数,否则会报错。

好了,后端接收前端传过来的文件并保存到服务器然后返回url给前端就已经完成了。如果有什么问题,欢迎向我提问,看到提问之后会及时解答!

-----------------------------------------------------------------------------------------------------------------------------

文章中只有后端保存文件部分,对于前端上传文件可以进主页查看!

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值