七牛云图片存储Java篇
一 【程序员头痛的问题】
1 . 海量存储 在互联网的应用中,用户会上传大量的图片以及文件,而且访问频繁,如果文件都以传统方式存在服务器磁盘上(单节点),对CPU,内存,磁盘空间和网络带宽等服务器资源都是很大的挑战。主要体现在:
单节访问,并发问题
单节点存储,单点故障
访问权限控制
扩容(水平扩展)
2 . 图片处理
为了满足前端显示需要,一个图片在不同的地方需要不同的尺寸,需要剪裁或压缩图片。
原图太大,带宽的资源非常宝贵,为了节省带宽,需要图片压缩。
图片鉴黄
图片加水印
二 【传统解决方案】
FastDFS,一个开源的轻量级,需自己部署和维护,解决海量存储问题,但是成本高。
GraphicsMagick,号称图像处理领域的瑞士军刀,解决图片处理问题,但是一样成本高。
三 【七牛云解决方案】
优点:
高并发
高可用
易扩展
低成本
四 【七牛的安全机制】
上传凭证:上传文件的时候,需要把uploadToken通过http post传给七牛服务器才能完成身份验证。
管理:如音视频转码,视频加水印,持久化处理等操作时,需要在调用api接口时,在http header 里加入Authorization : QBox AccessToken
下载:如果空间为私有访问时,下载文件需要下载凭证,就是在http get url 后面加入token参数
五 【注册账号&快速体验】
1 . 快速入门,参考七牛官方文档:
https://developer.qiniu.com/kodo/manual/1233/console-quickstart#step1
注:快速入门 会创建一个存储空间(bucket),后面生成uploadToken需要用到。
2 .生成uploadToken, 因为我们通常是通过api接口上传图片的,根据七牛的安全机制,我们需要先生成uploadToken,然后把uploadToken作为post的参数,保证上传的安全性
uploadToken生成算法
AccessKey:必须参数,可以在七牛后台生成
SecretKey:必须参数,可以在七牛后台生成
bocket :必须参数,快速入门里已经创建,名为:test
key :可选参数,如果加了该参数,上传文件时,必须和这里的key保持一致
六 【在Java中实战】
本篇文章采用的是SSM框架结构
1.在pom.xml中引入两个jar包(采用七牛云官方提供的SDK)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.2.7</version>
</dependency>
2.创建index.html页面
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/testUpload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit">上传</button>
</form>
</body>
</html>
3.创建FileUtil.java(验证图片后缀名)
public class FileUtil {
// 图片允许的后缀扩展名
public static String[] IMAGE_FILE_EXTD = new String[] { "png", "bmp", "jpg", "jpeg","pdf" };
public static boolean isFileAllowed(String fileName) {
for (String ext : IMAGE_FILE_EXTD) {
if (ext.equals(fileName)) {
return true;
}
}
return false;
}
}
4.创建QiniuService.java
@Service
public class QiniuService {
private static final Logger logger = LoggerFactory.getLogger(QiniuService.class);
// 设置好账号的ACCESS_KEY和SECRET_KEY
String ACCESS_KEY = "###################";
String SECRET_KEY = "###################";
// 要上传的空间
String bucketname = "####";
// 密钥配置
Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);
// 构造一个带指定Zone对象的配置类,不同的七云牛存储区域调用不同的zone
Configuration cfg = new Configuration(Zone.zone0());
// ...其他参数参考类注释
UploadManager uploadManager = new UploadManager(cfg);
// 测试域名,只有30天有效期
private static String QINIU_IMAGE_DOMAIN = "http://############/";
// 简单上传,使用默认策略,只需要设置上传的空间名就可以了
public String getUpToken() {
return auth.uploadToken(bucketname);
}
public String saveImage(MultipartFile file) throws IOException {
try {
int dotPos = file.getOriginalFilename().lastIndexOf(".");
if (dotPos < 0) {
return null;
}
String fileExt = file.getOriginalFilename().substring(dotPos + 1).toLowerCase();
// 判断是否是合法的文件后缀
if (!FileUtil.isFileAllowed(fileExt)) {
return null;
}
String fileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + fileExt;
// 调用put方法上传
Response res = uploadManager.put(file.getBytes(), fileName, getUpToken());
// 打印返回的信息
if (res.isOK() && res.isJson()) {
// 返回这张存储照片的地址
return QINIU_IMAGE_DOMAIN + JSONObject.parseObject(res.bodyString()).get("key");
} else {
logger.error("七牛异常:" + res.bodyString());
return null;
}
} catch (QiniuException e) {
// 请求失败时打印的异常的信息
logger.error("七牛异常:" + e.getMessage());
return null;
}
}
}
在我们创建存储空间的时候,会选择地区,Zone.zone0()这里代表华东区,如果是华北区则应该写Zone.zone1(),其他地区请查询七牛云文档
5.创建Controller
@Controller
public class TestController {
@Autowired
private QiniuService qiniuService;
@RequestMapping(value = "/testUpload", method = RequestMethod.POST)
@ResponseBody
public String uploadImage(@RequestParam("file") MultipartFile file,HttpServletRequest request) {
if(file.isEmpty()) {
return "error";
}
try {
String fileUrl=qiniuService.saveImage(file);
return "success, imageUrl = " + fileUrl;
} catch (IOException e) {
e.printStackTrace();
}
return "fail";
}
}
7.图片处理
url?Imageslim :图片瘦身
url? imageView2/0/w/<Width>/h/<Height> :等比缩放,不裁剪
url? imageView2/1/w/<Width>/h/<Height> :等比缩放,居中裁剪
明明可以靠脸,偏偏要靠技术
与其相忘于江湖,不如扫个二维码