图床——基于七牛JS-SDK和KVDB


原文链接:图床——基于七牛JS-SDK和KVDB

浏览

上传

服务端获取token

# -*- coding: utf-8 -*-
__author__ = 'Sky'

import qiniu
from datetime import datetime
import config


def get_token():
    q = qiniu.Auth(config.QINIU_ACCESS_KEY, config.QINIU_SECRET_KEY)
    # print str(datetime.now())
    token = q.upload_token(config.PIC_BUCKET)
    return token

JS上传到七牛

详细使用可参考七牛JS-SDK

var uploader = Qiniu.uploader({
    runtimes: 'html5,flash,html4',
    browse_button: 'pickfiles',
    container: 'container',
    drop_element: 'container',
    max_file_size: '100mb',
    filters: {
        mime_types: [
            { title: "图片文件", extensions: "jpg,gif,png,bmp" }
        ],
        prevent_duplicates: true //不允许队列中存在重复文件
    },
    flash_swf_url: '/static/js/plupload/Moxie.swf',
    dragdrop: true,
    chunk_size: '4mb',
    uptoken_url: $('#uptoken_url').val(),
    domain: $('#domain').val(),
    auto_start: true,
    init: {
        'FilesAdded': function(up, files) {
            $('table').show();
            $('#success').hide();
            plupload.each(files, function(file) {
                var progress = new FileProgress(file, 'fsUploadProgress');
                progress.setStatus("等待...");
            });
        },
        'BeforeUpload': function(up, file) {
            var progress = new FileProgress(file, 'fsUploadProgress');
            var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
            if (up.runtime === 'html5' && chunk_size) {
                progress.setChunkProgess(chunk_size);
            }
        },
        'UploadProgress': function(up, file) {
            var progress = new FileProgress(file, 'fsUploadProgress');
            var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
            progress.setProgress(file.percent + "%", up.total.bytesPerSec, chunk_size);

        },
        'UploadComplete': function() {
            $('#success').show();
        },
        'FileUploaded': function(up, file, info) {
            var progress = new FileProgress(file, 'fsUploadProgress');
            progress.setComplete(up, info);
            var res = $.parseJSON(info);
            // 请求后台存储
            var domain = up.getOption('domain');
            //url = domain + encodeURI(res.key);
            var link = domain + res.key;
            var key = res.key;
            $.ajax({
                url:"/upQiniu",
                type: "POST",
                data: { key: key, url: link}
            })
            .done(function(data){
                if(data === 'error') {
                    alert('上传失败');
                    location.reload(true);
                }
            });
        },
        'Error': function(up, err, errTip) {
            $('table').show();
            var progress = new FileProgress(err.file, 'fsUploadProgress');
            progress.setError();
            progress.setStatus(errTip);
        }
        ,
        'Key': function(up, file) {
            //当前时间戳
            var key = new Date();
            return key.getTime()
        }
    }
});

保存信息到KVDB

  • KVDB封装,方便使用
    为什么通过字典生成字符串存储而不直接存储json?为什么要使用\x1e\x1f作为连接符?
# -*- coding: utf-8 -*-
__author__ = 'Sky'

import sae
import json
import sae.kvdb

class KvdbStorage():
    # 初始化kvdb
    def __init__(self):
        self.kv = sae.kvdb.KVClient()

    # 获取value
    def get_value(self, key):
        return self.kv.get(key)

    # 获取dict_value
    def get(self, key):
        string_value = self.kv.get(key)
        if string_value is None:
            return None
        return decode_dict(string_value)

    # 设置value
    def set_value(self, key, value):
        self.kv.set(key, value)

    # 设置dict_value
    def set(self, key, dict_value):
        string_value = encode_dict(dict_value)
        self.kv.set(key, string_value)

    # 批量获取key
    def getkeys_by_prefix(self, prefix, limit=100, marker=None):
        return list(self.kv.getkeys_by_prefix(prefix, limit=limit, marker=marker))

    # 批量获取key/value
    def get_by_prefix(self, prefix, limit=100, marker=None):
        return self.kv.get_by_prefix(prefix, limit=limit, marker=marker)

    # 删除key
    def delete(self, key):
        self.kv.delete(key)

# 编码字典
def encode_dict(my_dict):
    return "\x1e".join("%s\x1f%s" % x for x in my_dict.iteritems())

# 解码字典
def decode_dict(my_string):
    return dict(x.split("\x1f") for x in my_string.split("\x1e"))
  • 只存储了key和图片url,其他暂时是固定信息,便于以后扩展。
# 上传文件到七牛
@app.route('/upQiniu', methods=['POST', 'GET'])
def upQiniu():
    if request.form.get('key'):
        url = request.form.get('url')
        upkey = request.form.get('key')
        # 时间差,用于加载排序
        import time
        future_time = int(time.mktime(datetime.strptime('3000-01-01 00:00:00.000', "%Y-%m-%d %H:%M:%S.%f").timetuple()) * 1000)
        uid = future_time - int(upkey)
        # 存入DB
        key = 'picbed_%s' % uid
        object = 'Sunset Lake'
        words = 'A peaceful sunset view...'
        author = 'skyway'
        # print key
        data = {'upkey': upkey, 'object': object, 'words': words, 'author': author, 'url': url}
        kv.set(str(key), data)
        # kv.set_value(str(key), url)
        return 'success'

浏览

访问获取key

# 初始加载
key_values = kv.get_by_prefix('picbed_', 20, None)
# print sorted(kv.getkeys_by_prefix('picbed', 3, None))
data = tuple(key_values)
json_data = []
for item in data:
    tmp = {}
    tmp['key'] = item[0]
    if '\x1e' in item[1]:
        content = decode_dict(item[1])
        # print content
        tmp['url'] = content['url'] + "?imageView2/2/w/400/format/jpg"
        tmp['object'] = content['object']
        tmp['words'] = content['words']
        tmp['upkey'] = content['upkey']
        tmp['author'] = content['author']
    else:
        tmp['url'] = item[1] + "?imageView2/2/w/400/format/jpg"
        tmp['object'] = 'Sunset Lake'
        tmp['words'] = 'A peaceful sunset view...'
        tmp['upkey'] = item[1][-13:]
        tmp['author'] = 'skyway'
    json_data.append(tmp)
# data = sorted(data, reverse=True)
# print data
return render_template('PicBed.html', data=json_data, domain=config.PIC_DOMAIN)

瀑布流和数据加载

  • Server端返回json数据
# 加载更多
if request.form.get('key'):
    key = request.form.get('key')
    # print key
    key_values = kv.get_by_prefix('picbed_', 10, key)
    # print sorted(kv.getkeys_by_prefix('picbed', 3, key))
    data = tuple(key_values)
    # data = sorted(data, reverse=True)
    print data
    json_data = []
    for item in data:
        tmp = {}
        tmp['key'] = item[0]
        if '\x1e' in item[1]:
            content = decode_dict(item[1])
            # print content
            tmp['url'] = content['url'] + "?imageView2/2/w/400/format/jpg"
            tmp['object'] = content['object']
            tmp['words'] = content['words']
            tmp['upkey'] = content['upkey']
            tmp['author'] = content['author']
        else:
            tmp['url'] = item[1] + "?imageView2/2/w/400/format/jpg"
            tmp['object'] = 'Sunset Lake'
            tmp['words'] = 'A peaceful sunset view...'
            tmp['upkey'] = item[1][-13:]
            tmp['author'] = 'skyway'
        json_data.append(tmp)
    json_str = json.dumps(json_data)
    return json_str
  • 加载更多和渲染数据:
$(window).scroll(function () {
    var clientHeight = $(window).height(),
        scrollTop = $(window).scrollTop(),
        scrollHeight = $(document).height();
    if (!isScroll && (scrollHeight - clientHeight - scrollTop < 500)) {
        isScroll = 1;
        $('#loading').show();
        // 获取最后一个块的key
        var key = $('.grid:last-child').data('key');
        // 请求数据
        $.ajax({
            url:"/picbed",
            type: "POST",
            data: { key: key}
        })
        .done(function(data){
            if(data === 'error') {
                alert('加载失败');
                location.reload(true);
                return false;
            }
            var pics = JSON.parse(data);
            //没有更多了
            if(jQuery.isEmptyObject(pics)){
                $('#load_img').hide();
                $('#load_text').text('没有更多了!');
                $('#contain').BlocksIt('reload');
                return false;
            }

            $.each(pics, function(index, val){
                var add =
                        "
" + "
" + "" + "" + "" + "
" + "" + ""+ this.object +"" + "
" + "

"+ this.words +"

" + "
by " + this.author +"
" + "
"+ "
"; $("#contain").append(add); // 动态加载渲染图片 img_stop(); }); $('#contain').BlocksIt('reload'); }); } });
  • 瀑布流效果使用插件Blockits.js
    效果不是很好,会产生重叠

长图渲染

对于过长的图片,影响整个浏览的体验,于是超过一定长度的图片,超出部分隐藏,并在图片尾部添加波浪表示图片未展示完全。

// 渲染图片函数
var img_stop = function(){
    var height = 800;
    $('.img_load').each(function() {
        $(this).load(function(){
            if( $(this).height() > height){
                $(this).parent().parent().next().css('display', 'block');
            }
        });
    });
};

// 初始加载渲染图片
$(function(){
    img_stop();
});

var img_load = function(url, key) {
    var img = new Image();
    img.src = url;
    img.onload = load_img(img, key);
    function load_img(img, key){
        var height = img.height;
        if( height > 500){
            var str = 'div[data-key=' + key + ']';
            $(str).find('.stop').css('display', 'block');
        }
    }
};

效果

  • PC端


    浏览

    上传

    预览
  • 移动端


    浏览
    上传
    预览

GitHub源码

你可能感兴趣的:(图床——基于七牛JS-SDK和KVDB)