项目亮点之云存储

#上传图片到七牛云,做云存储

com.nowcoder.controller.NewsController:

    /**
     *
     * @param file 向服务器上传的图片的二进制流
     * @return
     */
    //图片传输的时候就是二进制流,不需要模板渲染,所以用@ResponseBody
    @RequestMapping(value = "/uploadImage/",method = RequestMethod.POST)
    @ResponseBody
    public String uploadImage(@RequestParam("file") MultipartFile file){
      try{
          //上传图片到本地
          //String fileUrl=newsService.saveImage(file);
          //上传图片到七牛云
          String fileUrl = qiniuService.saveImage(file);
          if (fileUrl==null){
              return ToutiaoUtil.getJSONString(1, "上传图片失败");
          }
          return ToutiaoUtil.getJSONString(0, fileUrl);
      }catch (Exception e){
          logger.error("上传图片失败"+e.getMessage());
          return ToutiaoUtil.getJSONString(1,"上传失败");
      }
    }

com.nowcoder.service.QiniuService:

大致思路:通过上传文件的文件名,检查其后缀(fileExt)是否为服务支持的后缀,然后通过UUID随机产生(String)fileName+fileExt,最后上传的文件在云中的名字:QINIU_IMAGE_DOMAIN+fileName+fileExt。

@Service
public class QiniuService {
    private static final Logger logger = LoggerFactory.getLogger(QiniuService.class);
    //...生成上传凭证,然后准备上传
    //设置好账号的ACCESS_KEY和SECRET_KEY
    String accessKey = "S_FdXUJAL7pSpDx-NUo8TaYzj2rJbsEPEAiZ8FrL";
    String secretKey = "HjtyyBQEcjrvpqM0zqTo05vcWrNaKD1LzhQDURhf";
    String bucket = "toutiao";

    private static String QINIU_IMAGE_DOMAIN = "http://pnmtwczgg.bkt.clouddn.com/";
    UploadManager uploadManager = new UploadManager();
    //密钥配置
    Auth auth = Auth.create(accessKey, secretKey);

  //核心方法
    public String saveImage(MultipartFile file) throws IOException {

    //简单上传,使用默认策略,只需要设置上传的空间名就可以了
    String upToken = auth.uploadToken(bucket);

try {
    int dotPos = file.getOriginalFilename().lastIndexOf(".");
    if (dotPos < 0) {
        return null;
    }
    String fileExt = file.getOriginalFilename().substring(dotPos + 1).toLowerCase();
    if (!ToutiaoUtil.isFileAllowed(fileExt)) {
        return null;
    }
    //文件在云上的存储名
    String fileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + fileExt;
    //调用put方法上传
    /**
     *  file.getBytes():图片的字节流
     *  fileName:随机生成的图片名
     *  upToken:你指定存储的云空间
     */
    Response response = uploadManager.put(file.getBytes(), fileName, upToken);
    //打印返回的信息
    if (response.isOK() && response.isJson()) {

        return QINIU_IMAGE_DOMAIN + JSONObject.parseObject(response.bodyString()).get("key");
    } else {
        logger.error("七牛异常:" + response.bodyString());
        return null;
    }
    } catch (QiniuException e) {
    // 请求失败时打印的异常的信息
    logger.error("七牛异常:" + e.getMessage());
    return null;
        }
    }
}

#优势:

1.图片做单独的服务器,cdn内容分发网络,内容分发到各个节点,能够更快的访问静态文件。

2.云上有封装好的附加功能,比如:可以做实时缩图和实时切图,或者鉴黄。

CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。

#知识点补充:

##什么是MultipartFile?

MultipartFile是spring类型,代表HTML中form data方式上传的文件,包含二进制数据+文件名称。

什么是CDN?

CDN的全称是==Content Delivery Network==,即内容分发网络。CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。

#疑问:

##图片上传到云上,其中的过程?

先来看

/**
var oPopupUpload = new PopupUpload({

});
 */
(function (window) {
    var PopupUpload = Base.createClass('main.component.PopupUpload');
    var Popup = Base.getClass('main.component.Popup');
    var Upload = Base.getClass('main.component.Upload');
    var Component = Base.getClass('main.component.Component');
    var Util = Base.getClass('main.base.Util');

    Base.mix(PopupUpload, Component, {
        _tpl: [
            '<div>',
              '<div class="form-group">',
                '<div class="form-group">',
                    '<label class="col-sm-2 control-label">上传图片</label>',
                    '<div class="js-image-container col-sm-10">',
                        '<a href="javascript:void(0);" class="btn btn-info btn-upload js-upload-btn" style="diplay:inline-block;position:relative;">上传图片</a>',
                    '</div>',
                '</div>',
                  '<div class="form-group"><label class="col-sm-2 control-label">标题</label><div class="col-sm-10"><input class="js-title form-control" type="text"></div></div>',
                  '<div class="form-group"><label class="col-sm-2 control-label">链接</label><div class="col-sm-10"><input class="js-link form-control" type="text"></div></div>',
                  '<div class="form-group">',
                        '<div class="col-lg-10 col-lg-offset-2">',
                            '<input type="submit" value="提交" class="js-submit btn btn-default btn-info">',
                        '</div>',
                    '</div>',
            '</div>'].join(''),
        listeners: [{
            name: 'render',
            type: 'custom',
            handler: function () {
                var that = this;
                var oEl = that.getEl();
                var oUploadBtn = oEl.find('a.js-upload-btn');
                new Upload({
                    targetEl: oUploadBtn,
                    url: '/uploadImage/',
                    check: function (oFile, sType, nFileSize) {
                        var sMsg = nFileSize === 0 ? '文件大小不能为0' : /image/gi.test(sType || '') ? '' : '文件格式不正确';
                        sMsg && alert(sMsg);
                        return !sMsg;
                    },
                    call: function (oResult) {
                        var sUrl = $.trim(oResult.msg);
                        if (oResult.code !== 0) {
                            return alert('出现错误,请重试');
                        }
                        that.image = sUrl;
                        that.showImage(sUrl);
                    }
                });
            }
        }, {
            name: 'click input.js-submit',
            handler: function () {
                var that = this;
                var oEl = that.getEl();
                var sTitle = $.trim(oEl.find('input.js-title').val());
                var sLink = $.trim(oEl.find('input.js-link').val());
                if (!sTitle) {
                    return alert('标题不能为空');
                }
                if (!sLink) {
                    return alert('链接不能为空');
                }
                if (!that.image) {
                    return alert('图片不能为空');
                }
                if (that.requesting) {
                    return;
                }
                that.requesting = true;
                $.ajax({
                    url: '/user/addNews/',
                    method: 'post',
                    data: {image: that.image, title: sTitle, link: sLink},
                    dataType: 'json'
                }).done(function (oResult) {
                    that.emit('done');
                }).fail(function (oResult) {
                    alert('出现错误,请重试');
                }).always(function () {
                    that.requesting = false;
                });
            }
        }]
})(window);

我可以看到:有2个function,一个是触发URL:/uploadImage/;一个触发:/user/addNews/

触发的url与NewsController中方法的url对应,如/user/addNews/与addNews方法上的@RequestMapping(path={“/user/addNews/“}对应。

通俗点讲,

  1. 当点击上传图片,并选择图片确定,这时会执行/uploadImage/方法,并返回经过处理的JSON串,JSON串=带有七牛外连接+图片名字(UUID生成)+后缀名。前端收到后端返回的JSON串,根据code值来判断是否上传成功。这是一个典型的前端和后端的交互根据json串。
  2. 当我们点击提交时,前端会将访问URL锁定在/user/addNews/下,并使用POST方法,将data域中的image(就是步骤1中图片的路径名),title和link与addNews方法中的参数绑定,进而将这条咨询添加到数据库中。

com.nowcoder.controller.NewsController:

    /**
     *
     * @param file 向服务器上传的图片的二进制流
     * @return
     */
    //图片传输的时候就是二进制流,不需要模板渲染,所以用@ResponseBody
    @RequestMapping(value = "/uploadImage/",method = RequestMethod.POST)
    @ResponseBody
    public String uploadImage(@RequestParam("file") MultipartFile file){
      try{
          //上传图片到本地
          //String fileUrl=newsService.saveImage(file);
          //上传图片到七牛云
          String fileUrl = qiniuService.saveImage(file);
          if (fileUrl==null){
              return ToutiaoUtil.getJSONString(1, "上传图片失败");
          }
          return ToutiaoUtil.getJSONString(0, fileUrl);
      }catch (Exception e){
          logger.error("上传图片失败"+e.getMessage());
          return ToutiaoUtil.getJSONString(1,"上传失败");
      }
    }
    //增加咨询
    @RequestMapping(value = "/user/addNews/",method = RequestMethod.POST)
    @ResponseBody
    public String addNews(@RequestParam("image") String image,
                          @RequestParam("title") String title,
                          @RequestParam("link") String link){
      try {
          News news = new News();
          news.setCreatedDate(new Date());
          news.setTitle(title);
          news.setImage(image);
          news.setLink(link);
          if (hostHolder.getUser() != null) {
              news.setUserId(hostHolder.getUser().getId());
          }
          //设置了一个匿名用户
          else {
              news.setUserId(3);
          }
          newsService.addNews(news);
          return ToutiaoUtil.getJSONString(0);
      }catch (Exception e){
          logger.error("添加失败"+e.getMessage());
          return ToutiaoUtil.getJSONString(1,"添加失败!");
      }
    }

com.nowcoder.util.ToutiaoUtil:

返回JSON串的处理函数:

    public static String getJSONString(int code, String msg) {
        JSONObject json = new JSONObject();
        json.put("code", code);
        json.put("msg", msg);
        return json.toJSONString();
    }

可以看到,json串中有2个key,codemsg

##操作效果图:

使用postman:

可以看到uploadImage方法返回的json串:

{“msg”:”http://pp5tb1vb6.bkt.clouddn.com/eb9b3019211242e6928fdc94a6c8fda3.jpg","code":0}

前端根据”code”键值对判断是否上传成功;上传成功(就是”code”:0)后,通过”msg”取得图片在云上存储的位置,将其作为url:/user/addNews/对应方法addNews(String image,String title,String link)中参数image,传入方法中。

屏幕快照 2019-03-30 下午1.26.04

##在云上的存储情况:

屏幕快照 2019-03-30 下午1.27.43

在数据库的存储情况:

屏幕快照 2019-03-30 下午1.34.29


   转载规则


《项目亮点之云存储》 xuxinghua 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录
I I