简介
在日常项目开发中经常会用到图片,视频等文件存储的操作,但是文件如果一直存放在本地服务器中,可以会导致资源浪费,且访问速度也有所限制,这时我们就会考虑CDN加速或云端存储等方式来解决问题,这里就要介绍下本文用到的COS对象存储-安全稳定、海量、便捷、低延迟、低成本的云端存储服务。
COS对象存储
对象存储(Cloud Object Storage,COS)是腾讯云提供的面向非结构化数据,支持 HTTP/HTTPS 协议访问的分布式存储服务,它能容纳海量数据并保证用户对带宽和容量扩充无感知,可以作为大数据计算与分析的数据池。腾讯云 COS 提供网页端管理界面、多种语言的 SDK 以及命令行和图形化工具,并且完全兼容 S3 的 API 接口,方便用户直接使用社区工具和插件,COS 还可以和其他云产品结合,比如利用 CDN 的全球节点提供加速服务,利用数据万象的图片处理能力提供一站式图片解决方案等(详细介绍)
案例实现
- 本文使用的是腾讯云提供的COS服务,每个月提供50G存储容量,10G流量,对于一般的博客网站,以及项目测试来说绰绰有余
- 腾讯云对象存储 COS 除了提供多种 API 接口,还提供了丰富多样的 SDK 供开发者使用,如Java、Python、Js等…,本项目后台基于SpringMVC实现,前端通过LayUi框架的文件上传模块结合实现
- 存储桶相应的还有防盗链设置,跨域规则设置,读写权限设置,以及相应的CDN加速服务
代码
代码语言:javascript复制package cn.mall.controller.portal;
import cn.mall.common.ServerResponse;
import cn.mall.util.PropertiesUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Controller
@RequestMapping("/upload/")
public class UploadController {
//密钥请前往腾讯云后台查询
private static String secretId="*************";
private static String secretKey="*************";
private static String bucketName="你的存储桶名称";
private static String RegionName="存储桶所属地域";
/**
* 文件上传
* @param file
* @param session
* @return
*/
@RequestMapping(value = "upload_image_cos.do",method = RequestMethod.POST)
@ResponseBody
public Object Upload(@RequestParam(value = "file") MultipartFile file, HttpSession session){
if(file == null){
return new UploadMsg(0,"文件为空",null);
}
//获取文件上传原名
String oldFileName = file.getOriginalFilename();
String eName = oldFileName.substring(oldFileName.lastIndexOf("."));
//通过UUID随机生成新的文件名
String newFileName = UUID.randomUUID() eName;
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
// 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region(RegionName));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式
String bucketName = this.bucketName;
// 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20 M 以下的文件使用该接口
// 大文件上传请参照 API 文档高级 API 上传
File localFile = null;
try {
//创建临时文件
localFile = File.createTempFile("temp",null);
file.transferTo(localFile);
// 指定要上传到 COS 上的路径
String key = PropertiesUtil.getProperty("cos_key_name") newFileName;
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile);
PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);
return new UploadMsg(1,"上传成功", newFileName);
} catch (IOException e) {
return new UploadMsg(-1,e.getMessage(),null);
} finally {
// 关闭客户端(关闭后台线程)
cosclient.shutdown();
}
}
//自定义JSON消息体
private class UploadMsg {
public int status;
public String msg;
public String path;
public UploadMsg() {
super();
}
public UploadMsg(int status, String msg,String path){
this.status =status;
this.msg =msg;
this.path =path;
}
}
}
代码语言:javascript复制<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>商品添加</title>
<link rel="stylesheet" href="../assets/layui/css/layui.css">
</head>
<body>
<form class="layui-form column-content-detail">
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-form-item">
<label class="layui-form-label">商品标题:</label>
<div class="layui-input-block">
<input type="text" name="name" required lay-verify="required" placeholder="请输入商品标题" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类:</label>
<div class="layui-input-block">
<select name="categoryId" lay-verify="required">
<option value="">请选择分类</option>
<option value="100001">家用电器</option>
<option value="100002">数码3C</option>
<option value="100003">服装箱包</option>
<option value="100004">食品生鲜</option>
<option value="100005">酒水饮料</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图像上传:</label>
<div class="layui-input-block">
<img id="upload_img" src="../images/default_img.png" width="100" height="100">
<button type="button" class="layui-btn" id="test1">
<i class="layui-icon"></i>上传图片
</button>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">商品介绍:</label>
<div class="layui-input-block">
<textarea class="layui-textarea layui-hide" name="detail" lay-verify="detail" id="LAY_demo_editor"></textarea>
</div>
</div>
<input type="hidden" id="mainImage" name="mainImage" required value="default_img.png" class="layui-input">
<input type="hidden" id="status" name="status" value="1" class="layui-input">
<div class="layui-form-item">
<label class="layui-form-label">商品库存:</label>
<div class="layui-input-block">
<input type="text" name="stock" required lay-verify="number" placeholder="请输入商品库存" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">商品价格:</label>
<div class="layui-input-block">
<input type="text" name="price" required lay-verify="number" placeholder="请输入商品价格" autocomplete="off" class="layui-input">
</div>
</div>
</div>
</div>
<div class="layui-form-item" style="padding-left: 10px;">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="add_product">立即提交</button>
<button id="reset" type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<script src="../js/cos-js-sdk-v5.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../js/jquery-1.10.2.js" type="text/javascript" charset="utf-8"></script>
<script src="../assets/layui/layui.all.js"></script>
<script>
layui.use(['form', 'jquery', 'laydate', 'layer', 'laypage', 'element', 'upload', 'layedit'], function() {
var form = layui.form,
layer = layui.layer,
$ = layui.jquery,
laypage = layui.laypage,
laydate = layui.laydate,
layedit = layui.layedit,
element = layui.element,
upload=layui.upload;
//创建一个编辑器
var editIndex = layedit.build('LAY_demo_editor', {
tool: ['strong' //加粗
, 'italic' //斜体
, 'underline' //下划线
, 'del' //删除线
, '|' //分割线
, 'left' //左对齐
, 'center' //居中对齐
, 'right' //右对齐
, 'link' //超链接
, 'unlink' //清除链接
, 'image' //插入图片
],
height: 100
});
var uploadInst = upload.render({
elem: '#test1' //绑定元素
,url:'../upload/upload_image_cos.do'//后台上传接口
,before: function(obj){ //obj参数包含的信息,跟 choose回调完全一致,可参见上文。
layer.msg('上传中',{icon: 16,time:0,shade:0.01});
}
,done: function(res, index, upload){
layer.closeAll('loading');
//status=1代表上传成功
if(res.status == 1){
layer.msg("上传成功",{icon:1});
//do something (比如将res返回的图片链接保存到表单的隐藏域)
$('#upload_img').attr('src','https://sr-1251242863.cos.ap-shanghai.myzijiebao.com/webdemo/images/' res.path);
$('#mainImage').val(res.path);
}
//获取当前触发上传的元素,一般用于 elem 绑定 class 的情况,注意:此乃 layui 2.1.0 新增
var item = this.item;
//文件保存失败
//do something
}
,error: function(){
layer.closeAll('loading');
//请求异常回调
layer.msg("上传失败,请重试",{icon:2});
}
,size:2048 //文件大小限制
,number:1 //文件数量限制
,accept: 'images' //文件类型限制
,acceptMime: 'image/jpg, image/png' //选择窗口属性
});
});
</script>
</body>
</html>