在实际项目中,文件上传是很多项目必不可少的一个功能。那么在 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); } }
更多详细的配置,请参考官方文档:初始化
二、文件上传
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 的详细内容,请参考官方文档:Post Policy
当文件上传成功后,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
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); } }
到此这篇关于Spring Boot项目中实现文件上传功能的示例的文章就介绍到这了,更多相关Spring Boot实现文件上传内容请搜索易盾网络以前的文章或继续浏览下面的相关文章希望大家以后多多支持易盾网络!