前言
项目中涉及到图片的都会使用阿里云oss文件上传,为了便于开发,特编写此文档。
前提条件
已经获取到阿里云oss的accessid和accesskey,且已经创建阿里云oss的bucket。其中,bucket的权限为公共读
,这样可以通过bucket和endpoint的拼接查询图片路径。
1、在pom中添加相关依赖
<!--阿里云-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
<!--整合Knife4j-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox-swagger2.version}</version>
</dependency>
<!--swagger-ui-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-swagger-ui.version}</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2、添加配置文件
ali:
oss:
accessId: xxx
accessKey: xxxx
bucket: testaaaa
endpoint: # Endpoint:在阿里云oss控制台查看自己使用的endpoint,eg: oss-cn-shanghai.aliyuncs.com
tempFile: D:/temp/
showUri: https://bucket名.enpoint/ #在系统中没有用到,只是一个记录作用,使用这个地址拼接上传的文件key查询图片
3、添加OSS的相关Java配置
用于配置OSS的连接客户端的OSSClient
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "ali.oss")
public class AliyunConfig {
private String accessId;
private String accessKey;
private String bucket;
private String endpoint;
private String tempFile;
private String showUri;
}
4、阿里云 oss 上传工具类
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.PutObjectResult;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.apache.poi.ss.usermodel.PictureData;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.time.LocalDateTime;
import java.util.UUID;
/**
* 阿里云 oss 上传工具类
*/
@Component
@Slf4j
public class AliOssUtil {
private AliOssUtil(){}
static String endpoint = "";
static String accessKeyId = "";
static String accessKeySecret = "";
static String bucketName = "";
static String tempFile = "C:/temp/";
/**
* 上传图片到 Oss
* @param key
* @param multipartFile
*/
public static String upload(String key, MultipartFile multipartFile){
String suffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
suffix = StringUtils.isNotBlank(suffix) ? suffix : "jpg";
String filePath = String.join("", tempFile, key,".",suffix);
key = String.join("",key,".",suffix);
File file = null;
try {
FileUtil.mkdir(new File(tempFile));
file = FileUtil.writeFromStream(multipartFile.getInputStream(), filePath);
if(!file.exists()){
throw new RuntimeException("上传的文件,保存到本地失败!");
}
log.info("[文件上传] 文件上传到本地成功,路径:{}",filePath);
} catch (IOException e) {
e.printStackTrace();
}
log.info("[文件上传] 准备上传文件到Oss..");
//图片压缩
String filePathCopy=String.join("", tempFile, key,"_copy.",suffix);
File fileCopy = new File(filePathCopy);
try {
OutputStream out =new FileOutputStream(fileCopy);
BufferedImage bufferedImage = ImageIO.read(new FileInputStream(file));
Image image =bufferedImage.getScaledInstance(bufferedImage.getWidth(),bufferedImage.getHeight(),Image.SCALE_SMOOTH);
BufferedImage tag = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics graphics = tag.getGraphics();
graphics.drawImage(image, 0,0,null);
graphics.dispose();
ImageIO.write(tag,"jpg",out);
} catch (IOException e) {
throw new RuntimeException("请输入jpg格式的图片");
}
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
String path = String.join("", DateUtil.format(LocalDateTime.now(),"yyyy/MM/dd"),"/",key);
PutObjectResult putObjectResult = ossClient.putObject(bucketName, path, new File(filePathCopy));
log.info("[文件上传] 文件上传到Oss结果:{}", JSONObject.toJSONString(putObjectResult));
log.info("[文件上传] 删除本地图片:{}",FileUtil.del(file));
return path;
}
public static void upload(String key, File file){
log.info("[文件上传] 准备上传文件到Oss..");
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
String path = String.join("", DateUtil.format(LocalDateTime.now(),"yyyy/MM/dd"),"/",key);
PutObjectResult putObjectResult = ossClient.putObject(bucketName, path, file);
log.info("[文件上传] 文件上传到Oss结果:{}", JSONObject.toJSONString(putObjectResult));
// log.info("[文件上传] 删除本地图片:{}",FileUtil.del(file));
}
public static void main(String[] args) throws IOException {
String s = UUID.randomUUID().toString();
System.out.println(s);
File file = new File("C:\\Users\\iFound\\Desktop\\bb.png");
FileInputStream fileInputStream = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(),
ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
upload(s,multipartFile);
//upload(s,new File("C:\\Users\\m\\Desktop\\微信截图_20220916171520.png"));
}
/**
* 前端oss直传返回存储桶对象
*/
public static OssConfigVO ossUpload(String picture){
OssConfigVO ossConfigVO = new OssConfigVO();
ossConfigVO.setEndpoint(endpoint);
ossConfigVO.setAccessKeyId(accessKeyId);
ossConfigVO.setAccessKeySecret(accessKeySecret);
ossConfigVO.setBucketName(bucketName);
ossConfigVO.setTempFile(tempFile);
ossConfigVO.setPicture(picture);
System.out.println();
System.out.println(ossConfigVO);
System.out.println();
return ossConfigVO;
}
@Data
public static class OssConfigVO {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
private String tempFile;
private String picture;
}
@Value("${ali.oss.endpoint}")
public void setEndpoint(String endpoint) {
AliOssUtil.endpoint = endpoint;
}
@Value("${ali.oss.accessId}")
public void setAccessKeyId(String accessKeyId) {
AliOssUtil.accessKeyId = accessKeyId;
}
@Value("${ali.oss.accessKey}")
public void setAccessKeySecret(String accessKeySecret) {
AliOssUtil.accessKeySecret = accessKeySecret;
}
@Value("${ali.oss.bucket}")
public void setBucketName(String bucketName) {
AliOssUtil.bucketName = bucketName;
}
@Value("${ali.oss.tempFile}")
public void setTempFile(String tempFile) {
AliOssUtil.tempFile = tempFile;
}
}
5、controller层代码(根据实际业务修改)
@Api(tags = {"A-文件上传controller"})
@RestController
@AllArgsConstructor
public class UploadController {
@Autowired
private AliyunConfig aliyunConfig;
/**
* 图片上传
* @param file
* @return
*/
@ApiOperation("图片上传")
@PostMapping("/upload")
public Result<FileUploadOutVO> upload(@RequestParam("file") MultipartFile file) {
String fileKey = UUID.randomUUID().toString();
fileKey = AliOssUtil.upload(fileKey, file);
FileUploadOutVO upload = new FileUploadOutVO();
upload.setUrl(fileKey);
upload.setPrefix(aliyunConfig.getShowUri());
return Result.success(upload);
}
/**
* 图片回显前置路径
* @return
*/
@ApiOperation("图片回显前置路径")
@GetMapping("/getUrl")
public Result<FileUploadOutVO> getUrl() {
FileUploadOutVO upload = new FileUploadOutVO();
upload.setPrefix(aliyunConfig.getShowUri());
return Result.success(upload);
}
}
6、其他配置类
Result
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
@ApiModelProperty("响应状态,true-成功,false-其他异常")
private Boolean success;
/**
* 响应码,20000-成功;200001-其他异常
*/
@ApiModelProperty("响应码,20000-成功; 20001-其他异常")
private Integer code;
/**
* message
*/
@ApiModelProperty("Message")
private String message;
/**
* 响应数据
*/
@Getter
@Setter
@ApiModelProperty("响应数据")
private T data;
public static <T> Result<T> success() {
return new Result<>(true, 20000, "操作成功", null);
}
public static <T> Result<T> success(T data) {
return new Result<>(true, 20000, "操作成功", data);
}
public static <T> Result<T> success(T data, String message) {
return new Result<>(true, 20000, message, data);
}
public static <T> Result<T> success(String message) {
return new Result<>(true, 20000, message, null);
}
public static <T> Result<T> fail() {
return new Result<>(false, 20001, "操作失败", null);
}
public static <T> Result<T> fail(T data) {
return new Result<>(false, 20001, "操作失败", data);
}
public static <T> Result<T> fail(String message, T data) {
return new Result<>(false, 20001, message, data);
}
public static <T> Result<T> fail(Integer code) {
return new Result<>(false, code, "操作失败", null);
}
public static <T> Result<T> fail(Integer code, String message) {
return new Result<>(false, code, message, null);
}
public static <T> Result<T> fail(String message) {
return new Result<>(false, 20001, message, null);
}
}
FileUploadOutVO
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class FileUploadOutVO implements Serializable {
@ApiModelProperty("图片路径")
private String url;
@ApiModelProperty("图片回显前置路径")
private String prefix;
}