首页 > 其他分享 >Spring Boot 实现文件上传

Spring Boot 实现文件上传

时间:2023-09-28 16:46:15浏览次数:30  
标签:String Spring oss Boot private callback aliyun 上传

在实际项目中,文件上传是很多项目必不可少的一个功能。那么在 Spring Boot 项目中又是如何来实现文件上传功能的呢?一般来说,上传的文件可以保存到项目根目录下的某一文件夹中,但这样做显然是不太合适的。因此我们选择将文件上传到专门的文件服务器中。很多云计算厂商都提供文件存储服务。这里我选择的是阿里云的对象存储(OSS)。

一、配置OSS

1. 导入SDK

首先,你需要注册阿里云的账号并开通对象存储服务。在准备工作完成之后,需要导入 JAVA 版本的 SDK,这里使用 maven 进行导入

<!-- 阿里云OSS对象存储 -->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.8.0</version>
</dependency>

2. 修改配置文件

导入完成后在 application.properties 配置文件中添加以下内容

# 节点域名
aliyun.oss.endpoint=oss-cn-xxxxxxx.aliyuncs.com
# 账户id
aliyun.oss.accessKeyId=xxxxxxxxxxxxx
# 账户密码
aliyun.oss.accessKeySecret=xxxxxxxxxxxxx
# bucket名称
aliyun.oss.bucketName=xxxxxxxxxxx
# 签名过期时间
aliyun.oss.policy.expire=300
# 上传文件的最大尺寸
aliyun.oss.maxSize=10
# 上传地址的前缀
aliyun.oss.dir.prefix=xxx
# 回调参数的请求地址
aliyun.oss.callback=http://www.xxxxxx.com/api/aliyun/oss/callback

以上内容在开通服务后均可获取到,请根据实际情况进行修改

3. 初始化

OSSClient是OSS的Java客户端,用于管理存储空间和文件等OSS资源。使用Java SDK发起OSS请求,您需要初始化一个OSSClient实例,并根据需要修改ClientConfiguration的默认配置项。

根据官方文档的描述,需要初始化一个ossClient实例并将其注入到Spring容器中,因此可以编写一个配置类OssConfig

@Configuration
@PropertySource(value = {"classpath:application.properties"}, encoding = "utf-8")
public class OssConfig {

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.accessKeyId}")
    private String accessKeyId;

    @Value("${aliyun.oss.accessKeySecret}")
    private String secretAccessKey;

    @Bean
    public OSS ossClient(){
        return new OSSClientBuilder().build(endpoint, accessKeyId, secretAccessKey);
    }
}

更多详细的配置,请参考官方文档:

初始化_Java_SDK 参考_对象存储 OSS-阿里云​help.aliyun.com/document_detail/32010.html

二、文件上传

1. 流程分析

我们以典型的表单上传为例,在使用对象存储OSS后,表单上传分为以下几个流程:

注:Policy表单域用于验证请求的合法性。例如可以指定上传的大小,可以指定上传的Object名称等,上传成功后客户端跳转到的URL,上传成功后客户端收到的状态码。

PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, DIR_PREFIX);
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
// 将Policy字符串进行base64编码
String policy = BinaryUtil.toBase64String(binaryData);
// 用OSS的AccessKeySecret对base64编码后的Policy进行签名
String signature = ossClient.calculatePostSignature(postPolicy);

前端向OSS服务器上传文件时要上传Policy表单域,OSS服务器将对Policy表单域的内容进行验证。关于 Post Policy 的详细内容,请参考官方文档:

PostObject_基础操作_关于Object操作_API 参考_对象存储 OSS-阿里云​help.aliyun.com/document_detail/31988.html#section-d5z-1ww-wdb

当文件上传成功后,OSS服务器会向应用服务器发起回调请求,具体流程如下:

用户只需要在发送给 OSS 的请求中携带相应的 Callback 参数,即能实现回调。

Callback 参数是由一段经过 base64 编码的 JSON 字符串(字段)。构建 callback 参数的关键是指定请求回调的服务器 URL(callbackUrl)以及回调的内容(callbackBody)。

// 上传回调参数
Callback callback = new Callback();
// 指定请求回调的服务器URL
callback.setCallbackUrl(CALLBACK);
//(可选)设置回调请求消息头中Host的值,即您的服务器配置Host的值。
// callback.setCallbackHost("yourCallbackHost");
// 设置发起回调时请求body的值。
callback.setCallbackBody("{\\\"filename\\\":${object},\\\"mineType\\\":${mimeType}}");
// 设置发起回调请求的Content-Type。
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
// 设置发起回调请求的自定义参数,由Key和Value组成,Key必须以x:开始。
// callback.addCallbackVar("x:dir", "value");

更详细的内容请阅读官方文档:

Callback_基础操作_关于Object操作_API 参考_对象存储 OSS-阿里云​help.aliyun.com/document_detail/31989.html

2. 功能实现

首先编写 Post Policy 封装对象OssPolicyResult

@Data
public class OssPolicyResult {

    @ApiModelProperty("用户id")
    private String accessKeyId;

    @ApiModelProperty("Post Policy经过base64编码过的字符串")
    private String policy;

    @ApiModelProperty("对policy签名后的字符串")
    private String signature;

    // @ApiModelProperty("对象的键值")
    // private String key;

    @ApiModelProperty("上传文件夹路径前缀")
    private String dir;

    @ApiModelProperty("oss对外服务的访问域名")
    private String host;

    @ApiModelProperty("上传成功后的回调设置")
    private String callback;
}

然后需自定义一个回调结果对象OssCallBackResult

@Data
public class OssCallBackResult {

    @ApiModelProperty("文件的链接")
    private String url;
    @ApiModelProperty("文件名称")
    private String filename;
    @ApiModelProperty("文件大小")
    private String size;
    @ApiModelProperty("文件的mimeType")
    private String  mimeType;
    @ApiModelProperty("图片文件的宽")
    private String width;
    @ApiModelProperty("图片文件的高")
    private String height;
}

注:以上内容可根据实际需要进行修改

之后编写 Service 接口及实现类

Service 接口:

public interface OssService {

    // 生成Post Policy
    OssPolicyResult policy();

    // 上传成功后的回调
    OssCallBackResult callback(Map<String, Object> requestBody);
}

Service 实现类:

@Slf4j
@Service
@PropertySource(value = {"classpath:application.properties"}, encoding = "utf-8")
public class OssServiceImpl implements OssService {

    @Value("${aliyun.oss.endpoint}")
    private String ENDPOINT;

    @Value("${aliyun.oss.accessKeyId}")
    private String ACCESS_KEY_ID;

    @Value("${aliyun.oss.accessKeySecret}")
    private String SECRET_ACCESS_KEY;

    @Value("${aliyun.oss.bucketName}")
    private String BUCKET_NAME;

    @Value("${aliyun.oss.policy.expire}")
    private int EXPIRE;

    @Value("${aliyun.oss.maxSize}")
    private int MAX_SIZE;

    @Value("${aliyun.oss.dir.prefix}")
    private String DIR_PREFIX;

    @Value("${aliyun.oss.callback}")
    private String CALLBACK;

    @Autowired
    private OSS ossClient;

    @Override
    public OssPolicyResult policy() {
        OssPolicyResult result = new OssPolicyResult();
        // 签名有效期
        long expireEndTime = System.currentTimeMillis() + EXPIRE * 1000;
        Date expiration = new Date(expireEndTime);
        // 文件名称
        // String filename = UUID.randomUUID().toString();
        // 文件大小
        long maxSize = MAX_SIZE * 1024 * 1024;
        // 提交节点
        String action = "http://" + BUCKET_NAME + "." + ENDPOINT;
        // 上传回调参数
        Callback callback = new Callback();
        // 指定请求回调的服务器URL
        callback.setCallbackUrl(CALLBACK);
        //(可选)设置回调请求消息头中Host的值,即您的服务器配置Host的值。
        // callback.setCallbackHost("yourCallbackHost");
        // 设置发起回调时请求body的值。
        callback.setCallbackBody("{\\\"filename\\\":${object}}");
        // 设置发起回调请求的Content-Type。
        callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
        // 设置发起回调请求的自定义参数,由Key和Value组成,Key必须以x:开始。
        // callback.addCallbackVar("x:dir", "value");
        try {
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, DIR_PREFIX);
            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
            // 将Policy字符串进行base64编码
            String policy = BinaryUtil.toBase64String(binaryData);
            // 用OSS的AccessKeySecret对base64编码后的Policy进行签名
            String signature = ossClient.calculatePostSignature(postPolicy);
            // 将callback配置进行base64编码
            String callbackData = BinaryUtil.toBase64String(OSSUtils.jsonizeCallback(callback).getBytes());
            // 返回结果
            result.setAccessKeyId(ACCESS_KEY_ID);
            result.setPolicy(policy);
            result.setSignature(signature);
            // result.setKey(filename);
            result.setDir(dir);
            result.setHost(action);
            result.setCallback(callbackData);
        } catch (Exception e) {
            log.error("签名生成失败", e);
        }
        return result;
    }

    @Override
    public OssCallBackResult callback(Map<String, Object> requestBody) {
        OssCallBackResult ossCallbackResult = new OssCallBackResult();
        // 文件名
        String filename = requestBody.get("filename").toString();
        // 文件链接
        String url = "https://" + BUCKET_NAME + "." + ENDPOINT + "/" + DIR_PREFIX + "/" + filename;
        ossCallbackResult.setUrl(url);
        return ossCallbackResult;
    }
}

添加 Controller 层:

@Api(tags = "阿里云对象存储接口")
@RequestMapping("/api")
@RestController
public class OssController {

    @Autowired
    private OssService ossService;

    @ApiOperation(value = "OSS上传签名生成")
    @GetMapping("/aliyun/oss/policy")
    public Object policy() {
        return ossService.policy();
    }

    @ApiOperation(value = "OSS上传成功回调")
    @PostMapping("/aliyun/oss/callback")
    public Object callback(@RequestBody Map<String, Object> requestBody) {
        return ossService.callback(requestBody);
    }
}

 

参考文章:http://blog.ncmem.com/wordpress/2023/09/28/spring-boot-%e5%ae%9e%e7%8e%b0%e6%96%87%e4%bb%b6%e4%b8%8a%e4%bc%a0/

欢迎入群一起讨论

 

 

标签:String,Spring,oss,Boot,private,callback,aliyun,上传
From: https://www.cnblogs.com/songsu/p/17736068.html

相关文章

  • Spring Cloud智慧工地云服务平台源码 PC端+APP端+数据大屏源码 开箱即用
    智慧工地云服务平台源码 PC端+APP端+数据大屏全套源码 自主版权智慧工地利用移动互联、物联网、云计算、大数据等新一代信息技术,彻底改变传统施工现场各参建方的交互方式、工作方式和管理模式,为建设集团、施工企业、监理单位、设计单位、政府监管部门等提供一揽子工地现场管理信......
  • SpringBoot笔记
    1.原理SpringApplication这个类主要做了以下四件事情:1、推断应用的类型是普通的项目还是Web项目2、查找并加载所有可用初始化器,设置到initializers属性中3、找出所有的应用程序监听器,设置到listeners属性中4、推断并设置main方法的定义类,找到运行的主类run方法剖析2.......
  • Spring Boot实现文件上传的两种方式
    最近的一个小项目里使用到了文件上传、下载功能,今天我打算梳理一下文件上传所涉及的技术及实现。内容主要包括两部分,如何通过纯Servlet的形式进行文件上传、保存(不通过Spring框架);另一部分是如何在SpringWebMVC中进行文件上传。01-从HTTP协议角度分析文件上传HTTP协......
  • Spring Framework框架
    SpringFramework框架一、含义:简称为Spring,是一个开源的、综合性的Java应用程序开发框架。它提供了一系列的功能和特性,用于开发企业级的Java应用程序。二、主要模块支持IoC和AOP的容器IoC(InversionofControl,控制反转):一种设计原则1.含义:它指将对象的创建、依赖关系的管理......
  • SpringMVC 的执行流程
    具体流程如下所示:用户发送出请求到前端控制器DispatcherServlet。DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。HandlerMapping找到具体的处理器(可查找xml配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。Dis......
  • Spring boot 处理大文件上传
    在Web上处理大文件上传时,可以使用以下方法来优化和处理大文件的上传:前端处理:在前端使用合适的文件上传库或组件,例如Dropzone.js、FineUploader等,它们提供了更好的用户体验和可靠的上传功能。使用分块上传(ChunkedUpload)技术,将大文件拆分成较小的块进行上传,以便提高上传的可靠性......
  • 最近正在集成SpringBoot与MyBatis-plus,体验感很好啊
    sqlCREATETABLE`class`(`id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'编号',`name`varchar(30)DEFAULTNULLCOMMENT'班级名',`floor`int(3)DEFAULTNULLCOMMENT'楼层',`teacher_id`int(11)DEFAULTNULLCOMMENT'老师......
  • 实战指南,SpringBoot + Mybatis 如何对接多数据源
    本文分享自华为云社区 《实战指南,SpringBoot+Mybatis如何对接多数据源》,作者:战斧。在我们开发一些具有综合功能的项目时,往往会碰到一种情况,需要同时连接多个数据库,这个时候就需要用到多数据源的设计。而Spring与Myabtis其实做了多数据源的适配,只需少许改动即可对接多数据源。......
  • springcloud gateway 获取响应体进行加密操作,byte[]转换String乱码
    记录一下困扰一星期的问题!在全局过滤器中,获取响应体进行加密操作,在拿到byte[]之后转成String,控制台打印出来是乱码,编码也加了UTF-8还是报错。publicMono<Void>filter(ServerWebExchangeexchange,GatewayFilterChainchain){ServerHttpResponseoriginalResponse=ex......
  • SpringBoot实现文件上传的多种方式
    我们平时在项目开发过程中,会遇到许多的文件上传与下载的需求,今天我们就来梳理一下文件上传的代码实现,基于SpringBoot快速搭建服务,集成文件上传功能,包括传统的文件上传方式,也拓展OSS对象存储方式。项目类型是Maven项目一、引入web依赖<dependency><groupId>org.springframework......