一.阿里云OSS文件上传接口
根据类型(type)查询分类接口已经开发完毕,接下来我们要开发第二个接口:使用阿里云OSS进行文件上传接口。
1.接口文档

在文件上传接口文档中,我们可以看到请求方式为POST,因此在controller层使用@PostMapping注解,路径为“/admin/common/upload”。请求的参数是MultipartFile类型的file。

返回值是String类型的参数,代表文件的url路径,前端通过该路径获得文件并渲染出来。 
2.配置阿里云OSS属性
既然要使用阿里云OSS,那么就要配置相关的属性。我们在application-dev.yml,即开发环境配置文件中配置相关的属性,然后在application.yml配置文件中引入。
application-dev.yml:
sky:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
host: localhost
port: 3306
database: sky_take_out
username: root
password:
alioss:
endpoint: https://oss-cn-nanjing.aliyuncs.com
bucket-name: sky-gjw-yhx
access-key-secret: *********************
access-key-id: ********************
server:
port: 8080
spring:
profiles:
active: dev
main:
allow-circular-references: true
datasource:
druid:
driver-class-name: ${sky.datasource.driver-class-name}
url: jdbc:mysql://${sky.datasource.host}:${sky.datasource.port}/${sky.datasource.database}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: ${sky.datasource.username}
password: ${sky.datasource.password}
mybatis:
#mapper配置文件
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.sky.entity
configuration:
#开启驼峰命名
map-underscore-to-camel-case: true
logging:
level:
com:
sky:
mapper: debug
service: info
controller: info
sky:
jwt:
# 设置jwt签名加密时使用的秘钥
admin-secret-key: itcast
# 设置jwt过期时间
admin-ttl: 7200000
# 设置前端传递过来的令牌名称
admin-token-name: token
alioss:
endpoint: ${sky.alioss.endpoint}
access-key-id: ${sky.alioss.access-key-id}
access-key-secret: ${sky.alioss.access-key-secret}
bucket-name: ${sky.alioss.bucket-name}
3.进行阿里云OSS工具类的开发
AliOssUtil.class
package com.sky.utils;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;
@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
/**
* 文件上传
*
* @param bytes
* @param objectName
* @return
*/
public String upload(byte[] bytes, String objectName) {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// 创建PutObject请求。
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
} 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();
}
}
//文件访问路径规则 https://BucketName.Endpoint/ObjectName
StringBuilder stringBuilder = new StringBuilder("https://");
stringBuilder
.append(bucketName)
.append(".")
.append(endpoint)
.append("/")
.append(objectName);
log.info("文件上传到:{}", stringBuilder.toString());
return stringBuilder.toString();
}
}
在AliOssUtil.class中我们要使用AliOssProperties.class中的属性。我们在AliOssProperties.class这个配置属性类上加上了@ConfigurationProperties注解,并在prefix当中指定了该属性在配置文件中的位置,这样在依赖注入AliOssProperties实现类对象时,该对象就会自动获取到位置文件中配置的属性。
package com.sky.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "sky.alioss") // 只有当对象由Spring容器创建时,属性绑定才会生效。如果new AliOssProperties(),再去get属性是获取不到的,必须使用依赖注入才行
@Data
public class AliOssProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
然后我们定义一个配置类OssConfiguration,用来将AliOssProperties中的属性配置给AliOssUtil对象并返回。
package com.sky.config;
import com.sky.properties.AliOssProperties;
import com.sky.utils.AliOssUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 定义一个配置类,用来将AliOssProperties中的属性配置给AliOssUtil对象并返回
*/
@Configuration
@Slf4j
public class OssConfiguration {
@Bean // 使用bean注解,这样就可以直接从IOC容器中获取到该AliOssUtil对象了,而不需要再OssConfiguration ossConfiguration = new OssConfiguration(),然后
// AliOssUtil aliOssUtil = ossConfiguration.aliOssUtil(aliOssProperties); aliOssProperties要通过以来后注入
@ConditionalOnMissingBean
public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties) {
log.info("开始创建阿里云文件上传工具类对象:{}",aliOssProperties);
return new AliOssUtil(aliOssProperties.getEndpoint(),
aliOssProperties.getAccessKeyId(),
aliOssProperties.getAccessKeySecret(),
aliOssProperties.getBucketName());
}
}
定义aliOssUtil方法用来返回AliOssUtil类的实现类对象,该方法的参数为aliOssProperties,(在 Spring 中,@Configuration
注解的类中的方法如果使用了 @Bean
注解,那么该方法的返回值会被注册到 Spring 的 IOC 容器中作为一个 Bean。方法的参数则会被 Spring 自动从 IOC 容器中获取,前提是这些参数本身也是容器中管理的 Bean。)然后调用该对象的get方法获取到属性值并传递给aliOssUtil对象。
4.定义Controller层
在Controller层中,使用@PostMapping("/upload")请求,要进行文件上传,我们设置Controller层来对前端传输过来的数据进行接收,对于普通的表单项,使用正常的参数变量进行接收即可,对于图片、文本、音视频等二进制类型的文件来说,使用一个特定的变量类型MultipartFile进行文件接收即可。要想成功接收到传输过来表单项,必须要保证表单项的名称和方法形参的名称要保持一致。叫file。

package com.sky.controller.admin;
import com.sky.config.OssConfiguration;
import com.sky.constant.MessageConstant;
import com.sky.properties.AliOssProperties;
import com.sky.result.Result;
import com.sky.utils.AliOssUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;
@RestController
@Slf4j
@Api(tags = "通用接口")
@RequestMapping("/admin/common")
public class CommonController {
@Autowired
private AliOssUtil aliOssUtil;
@ApiOperation("文件上传")
@PostMapping("/upload")
public Result<String> upload(MultipartFile file) {
log.info("文件上传:{}",file);
try {
// 获得原始文件名
String originalFilename = file.getOriginalFilename();
// 获得文件扩展名
String extension = originalFilename.substring(originalFilename.indexOf(".")); // indexOf:查找子字符串或字符在字符串中第一次出现的位置。substring(beginIndex):截取从 beginIndex(包含)到字符串末尾的子串
// 创建新名称:UUID+扩展名
String fileName = UUID.randomUUID().toString() + extension;
// 获得文件路径
String filePath = aliOssUtil.upload(file.getBytes(), fileName);// upload(byte[] bytes,String objectName) bytes:要上传的文件字节码 objectName:上传的文件在阿里云OSS中的名称
return Result.success(filePath); // 将文件在阿里云OSS中的路径返回给前端,以让前端进行渲染
} catch (IOException e) {
log.error("文件上传失败:{}",e);
}
return Result.error(MessageConstant.UPLOAD_FAILED);
}
}
使用.getOriginalFilename()获得原始文件名,然后获得文件名后缀。在使用工具类UUID生成UUID,拼接上文件名后缀,生成新的文件名。使用依赖注入将aliOssUtil注入并调用upload方法传入要上传的文件以及文件名。获得文件的上传路径,最后将该文件路径返回给前端,让前端进行渲染展示。
注意:阿里云 OSS 的 Endpoint 通常只需要填写域名部分,例如 oss-cn-hangzhou.aliyuncs.com
,而不需要包含 https://
。如果在配置中包含了 https://
,可能会导致生成的图片 URL 不正确。
