在做项目的过程中需要存储图片,所以选择将图片存储到七牛云上面,并将存储路径返回存储到数据库里。在网上看了很多篇文章,参考了一篇文章,结合自己的功能需求跑了一遍,记录下整个完成的过程。
目录
一、引入七牛云pom依赖:
二、application.yml:
三、在config里绑定配置文件:
四、在util里编写生成唯一图片名称的工具类:
五、编写上传文件接口UploadImageService:
六、 编写接口实现类UploadImageServiceImpl:
六、UploadController:
七、在postman测试一下:
一、引入七牛云pom依赖:
一开始我是直接在七牛云官方文档上直接复制下来的,但是在有些地方引用的时候说不能使用过时的类或方法,所以我就直接固定版本了。
<!-- 七牛云依赖-->
<!-- <dependency>-->
<!-- <groupId>com.qiniu</groupId>-->
<!-- <artifactId>qiniu-java-sdk</artifactId>-->
<!-- <version>[7.7.0, 7.7.99]</version>-->
<!-- </dependency>-->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.2.18</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>happy-dns-java</artifactId>
<version>0.1.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
二、application.yml:
这些都可以在七牛云找到
oss:
qiniu:
url: http://七牛云的外链域名
accessKey: 密钥AK
secretKey: 密钥SK
bucketName: 仓库名
三、在config里绑定配置文件:
package com.walnut.barter.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**七牛云配置类 绑定配置文件
* @ClassName QiNiuYunConfig
* @Description TODO
* @Author Flechazo_lalala
* Date 2021-11-17 17:02
* @Version 1.0
**/
@Data
@Configuration
public class QiNiuYunConfig {
@Value("${oss.qiniu.url}")
private String url;
@Value("${oss.qiniu.accessKey}")
private String AccessKey;
@Value("${oss.qiniu.secretKey}")
private String SecretKey;
@Value("${oss.qiniu.bucketName}")
private String BucketName;
}
四、在util里编写生成唯一图片名称的工具类:
package com.walnut.barter.common.util;
import java.util.UUID;
/**七牛云生成唯一图片名称的工具类
* @ClassName StringUtil
* @Description TODO
* @Author Flechazo_lalala
* Date 2021-11-17 17:07
* @Version 1.0
**/
public class StringUtil {
public static String getRandomImgName(String fileName) {
// 获取文件后缀
int index = fileName.lastIndexOf(".");
String suffix = fileName.substring(index);
//检验文件
if(".jpg".equals(suffix) || ".jpeg".equals(suffix) || ".png".equals(suffix)){
//改变上传到服务器的文件名 uuid + suffix
// 生成UUID
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
String path = uuid + suffix;
return path;
}else{
throw new IllegalArgumentException();
}
}
}
五、编写上传文件接口UploadImageService:
package com.walnut.barter.service;
import org.springframework.web.multipart.MultipartFile;
/**
* @ClassName UploadImageService
* @Description TODO
* @Author Flechazo_lalala
* Date 2021-11-17 17:09
* @Version 1.0
**/
public interface UploadImageService {
/**
* 上传文件
* @param file
* @return
*/
String uploadQNImg(MultipartFile file);
}
六、 编写接口实现类UploadImageServiceImpl:
我是华南地区的所以是zone2,如果是其他地区的需要修改。
华东:zone0 华北:zone1 华南:zone2 北美:na0 东南亚:as0
package com.walnut.barter.service.impl;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.walnut.barter.common.util.StringUtil;
import com.walnut.barter.config.QiNiuYunConfig;
import com.walnut.barter.service.UploadImageService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
/**
* @ClassName UploadImageServiceImpl
* @Description TODO
* @Author Flechazo_lalala
* Date 2021-11-17 17:11
* @Version 1.0
**/
@Service
public class UploadImageServiceImpl implements UploadImageService {
private QiNiuYunConfig qiNiuYunConfig;
/**七牛文件上传管理器*/
private UploadManager uploadManager;
/**上传的token*/
private String token;
/**七牛认证管理*/
private Auth auth;
private BucketManager bucketManager;
public UploadImageServiceImpl(QiNiuYunConfig qiNiuYunConfig) {
this.qiNiuYunConfig = qiNiuYunConfig;
init();
}
private void init() {
// 我是华南地区的所以是zone2,如果是其他地区的需要修改
uploadManager = new UploadManager(new Configuration(Zone.zone2()));
auth = Auth.create(qiNiuYunConfig.getAccessKey(), qiNiuYunConfig.getSecretKey());
// 根据命名空间生成的上传token
bucketManager = new BucketManager(auth, new Configuration(Zone.zone2()));
token = auth.uploadToken(qiNiuYunConfig.getBucketName());
}
/**
* 上传文件
* @param file
* @return
*/
@Override
public String uploadQNImg(MultipartFile file) {
String resultImage = "失败";
try {
// 判断图片后缀,并使用工具类根据上传文件生成唯一图片名称,防止截断字符如“%00”
String fileName = file.getOriginalFilename();
String imgName = StringUtil.getRandomImgName(fileName);
//判断是否为恶意程序
//通过流的方式把文件转换为BufferedImage对象,获取宽和高,只有图片才具有宽高属性
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
if(bufferedImage == null || bufferedImage.getHeight()==0 || bufferedImage.getWidth()==0){
return resultImage;
}
// 上传图片文件
Response res = uploadManager.put(file.getInputStream(), imgName, token, null, null);
if (!res.isOK()) {
throw new RuntimeException("上传七牛出错:" + res.toString());
}
// 解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(res.bodyString(), DefaultPutRet.class);
// 直接返回外链地址
return getPrivateFile(imgName);
} catch (QiniuException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return "失败";
}
/**
* 获取私有空间文件
*
* @param fileKey
* @return
*/
@Override
public String getPrivateFile(String fileKey) {
String encodedFileName = null;
String finalUrl = null;
try {
encodedFileName = URLEncoder.encode(fileKey, "utf-8").replace("+", "%20");
String publicUrl = String.format("%s/%s", this.qiNiuYunConfig.getUrl(), encodedFileName);
//1小时,可以自定义链接过期时间
long expireInSeconds = 3600;
finalUrl = auth.privateDownloadUrl(publicUrl, expireInSeconds);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return finalUrl;
}
/**
* 根据空间名、文件名删除文件
* @param bucketName
* @param fileKey
* @return
*/
@Override
public boolean removeFile(String bucketName, String fileKey) {
try {
bucketManager.delete(bucketName, fileKey);
} catch (QiniuException e) {
e.printStackTrace();
}
return true;
}
}
六、UploadController:
最后是控制层啦UploadController
这里的ResultInfo是封装好的统一接口类,大家可以自己修改,无伤大雅。
package com.walnut.barter.controller;
import com.walnut.barter.common.lang.ResultInfo;
import com.walnut.barter.common.util.ResultInfoUtil;
import com.walnut.barter.domain.vo.QiniuVo;
import com.walnut.barter.service.UploadImageService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
/**
* @ClassName UploadController
* @Description TODO
* @Author Flechazo_lalala
* Date 2021-11-17 17:20
* @Version 1.0
**/
@Slf4j
@RestController
@RequestMapping("/qiniu")
public class UploadController {
@Autowired
private UploadImageService uploadImageService;
@ApiOperation("上传图片")
@PostMapping("/image")
public ResultInfo upLoadImage(@RequestParam("file") MultipartFile file){
String result = "失败";
QiniuVo qiniuVo = new QiniuVo();
if(!file.isEmpty()){
String path = uploadImageService.uploadQNImg(file);
if(path.equals(result)){
return ResultInfoUtil.buildError("上传失败");
}else{
System.out.println("七牛云返回的图片链接是:" + path);
qiniuVo.setPath(path);
return ResultInfoUtil.buildSuccess(qiniuVo);
}
}
return ResultInfoUtil.buildError("上传失败");
}
}
七、在postman测试一下:
1. 先是测试上传正确安全的图片
成功啦!再去七牛云确认一下,仓库里多了一个图片文件,并且文件链接和我返回的链接是一样的,复制文件链接也可以直接打开文件。
2. 再测试伪装成图片的病毒文件
对于文件的上传,一定要考虑文件的安全性!
好啦,这就是我的完成过程,如果有什么问题或者有什么想要补充的欢迎在评论里提出来,大家一起交流。