vlambda博客
学习文章列表

七牛云图片存储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

@Servicepublic 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

@Controllerpublic 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>  :等比缩放,居中裁剪



明明可以靠脸,偏偏要靠技术

与其相忘于江湖,不如扫个二维码