图片上传

大家好,我是IT修真院郑州分院第十期学员,一枚正直纯洁善良的JAVA程序员。

今天给大家分享一下,java任务扩展思考知识点——图片上传。

一、背景介绍

     在开发过程中,不论是做网页还是APP,基本上都会有图片上传的业务需求,最典型的就是注册账号之后需要用户上传头像或者用户验证的时候上传身份证照片。 而java中实现图片上传大概有两种形式:一种是使用jsp+servlet实现图片上传;一种是使用jsp+controller实现图片上传。 存储基本上也有两种形式,在数据库中直接存储blob类型的图片或者图片存储在服务器上并在数据库中存储箱对应的路径,绝大部分网站用后者。采用后者时我们就要学习使用第三方的API。

     API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。(百度百科)

     其实调用使用第三方API,主要就是导入jar包,学习第三方文档中方法,了解各个方法的入参、返回值,通过判断返回值确定调用第三方的操作是否成功。

二、知识剖析

      如何通过腾讯cos完成图片的上传

     1.接收前端页面传来的MultipartFile类型文件,获得文件流,调用cosClient.putObject(bucketName, key, fileInputStream, objectMetadata)方法进行上传;
      2.接收前端页面传来的MultipartFile类型文件,将文件转存在服务器的某个位置,调用cosClient.putObject(bucketName, key, localFile)方法进行上传。

     如何通过腾讯cos完成前端页面图片的显示?

     1.调用getObjectContent()方法获取输入流,与HttpServletResponse的输出流对接在前端页面利用img标签发送请求显示;
     2.调用generatePresignedUrl(bucketName, key,expiration)方法获得签名的url路径,前端页面利用img标签显示;
     3.调用getObject(getObjectRequest, downFile)方法将图片下载到本地,再有本地转存前端img标签显示。

三、常见问题

     上传图片时如何完成图片的回显?(详见代码实战)

     1.filereader 的方法;
     2.createObjectURL的方法。

四、编码实战

     1.前端显示页面,index.jsp。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<h2>Hello World!</h2>
<a href="/index">主页</a>
<table border="1" align="center" style="border: 1px solid chartreuse;background:#dddddd;">
    <tr align="center">
        <th colspan="4">
            图片上传与下载显示
        </th>
    </tr>
    <tr align="center">
        <td>获取存储对象流显示</td>
        <td>
            <img src="/img1/view?key=img1.jpg" width="108" height="108" class="pimg">
        </td>
        <td>获取存储对象url显示</td>
        <td>
            <img src="http://picture-1256749558.cos.ap-beijing.myqcloud.com/img2.jpg?sign=q-sign-algorithm%3Dsha1%26q-ak%3DAKIDuwsdNW0xtlUInGnnkZMCc4LoLPVatXSu%26q-sign-time%3D1538397141%3B1538398941%26q-key-time%3D1538397141%3B1538398941%26q-header-list%3D%26q-url-param-list%3D%26q-signature%3Da18411dc1362a7d90ec500edabd8d0a52e185713" width="108" height="108" class="pimg">
        </td>
    </tr>
    <tr align="center">
        <td>
            流上传图片
        </td>
        <td>
            <input id="file1" type="file" name="multipartFile" accept="image/jpeg" onchange="showImg1(this)">
            <br>
            <img id="show1" src="" width="108" height="108" style="display: none" class="pimg"/>
            <button onclick="uploadImg1()">确认上传</button>
        </td>
        <td>
            转为文件上传图片
        </td>
        <td>
            <input id="file2" type="file" name="multipartFile" accept="image/jpeg" onchange="showImg2(this)">
            <br>
            <img id="show2" src="" width="108" height="108" style="display: none" class="pimg"/>
            <button onclick="uploadImg2()">确认上传</button>
        </td>
    </tr>

    <div id="outerdiv" style="position:fixed;top:0;left:0;background:rgba(0,0,0,0.7);z-index:2;width:100%;height:100%;display:none;">
        <div id="innerdiv" style="position:absolute;">
            <img id="bigimg" style="border:5px solid #fff;" src="" />
        </div>
    </div>
</table>
</body>
<script>
    function showImg1(file) {
        if (file) {
            var reads = new FileReader();
            img = file.files[0];
            reads.readAsDataURL(img);
            reads.onload = function (e) {
                document.getElementById("show1").src = this.result;
                document.getElementById("show1").style.display="block";
            };
        }
    }

    function showImg2(file) {
        if (file){
            //console.log(obj.files[0]);//这里可以获取上传文件的name
            var newsrc=getObjectURL(file.files[0]);
            document.getElementById("show2").src=newsrc;
            document.getElementById("show2").style.display="block";
        }
    }

    //建立一個可存取到該file的url
    function getObjectURL(file) {
        var url = null ;
        // 下面函数执行的效果是一样的,只是需要针对不同的浏览器执行不同的 js 函数而已
        if (window.createObjectURL!=undefined) { // basic
            url = window.createObjectURL(file) ;
        } else if (window.URL!=undefined) { // mozilla(firefox)
            url = window.URL.createObjectURL(file) ;
        } else if (window.webkitURL!=undefined) { // webkit or chrome
            url = window.webkitURL.createObjectURL(file) ;
        }
        return url ;
    }


    function uploadImg1() {
        var formData = new FormData();
        formData.append('multipartFile', $('#file1')[0].files[0]);
        $.ajax({
            type: "post",
            url: "/img1",
            data:formData,
            processData: false,
            contentType: false,
            success: function (data) {
                if (0==data){
                   alert("上传成功");
                }else {
                    alert("上传失败");
                }
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
               alert("上传失败")
            }
        });
    }

    function uploadImg2() {
        var formData = new FormData();
        formData.append('multipartFile', $('#file2')[0].files[0]);
        $.ajax({
            type: "post",
            url: "/img2",
            data:formData,
            processData: false,
            contentType: false,
            success: function (data) {
                if (0==data){
                    alert("上传成功");
                }else {
                    alert("上传失败");
                }
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                alert("上传失败")
            }
        });
    }

    $(".pimg").click(function(){
        var _this = $(this);//将当前的pimg元素作为_this传入函数
        imgShow("#outerdiv", "#innerdiv", "#bigimg", _this);
    });

    function imgShow(outerdiv, innerdiv, bigimg, _this) {
        var src = _this.attr("src");//获取当前点击的pimg元素中的src属性
        $(bigimg).attr("src", src);//设置#bigimg元素的src属性

        /*获取当前点击图片的真实大小,并显示弹出层及大图*/
        $("<img/>").attr("src", src).load(function () {
            var windowW = $(window).width();//获取当前窗口宽度
            var windowH = $(window).height();//获取当前窗口高度
            var realWidth = this.width;//获取图片真实宽度
            var realHeight = this.height;//获取图片真实高度
            var imgWidth, imgHeight;
            var scale = 0.8;//缩放尺寸,当图片真实宽度和高度大于窗口宽度和高度时进行缩放

            if (realHeight > windowH * scale) {//判断图片高度
                imgHeight = windowH * scale;//如大于窗口高度,图片高度进行缩放
                imgWidth = imgHeight / realHeight * realWidth;//等比例缩放宽度
                if (imgWidth > windowW * scale) {//如宽度扔大于窗口宽度
                    imgWidth = windowW * scale;//再对宽度进行缩放
                }
            } else if (realWidth > windowW * scale) {//如图片高度合适,判断图片宽度
                imgWidth = windowW * scale;//如大于窗口宽度,图片宽度进行缩放
                imgHeight = imgWidth / realWidth * realHeight;//等比例缩放高度
            } else {//如果图片真实高度和宽度都符合要求,高宽不变
                imgWidth = realWidth;
                imgHeight = realHeight;
            }
            $(bigimg).css("width", imgWidth);//以最终的宽度对图片缩放

            var w = (windowW - imgWidth) / 2;//计算图片与窗口左边距
            var h = (windowH - imgHeight) / 2;//计算图片与窗口上边距
            $(innerdiv).css({"top": h, "left": w});//设置#innerdiv的top和left属性
            $(outerdiv).fadeIn("fast");//淡入显示#outerdiv及.pimg
        });

        $(outerdiv).click(function () {//再次点击淡出消失弹出层
            $(this).fadeOut("fast");
        });
    }
</script>
</html>

    2.ImgController,注意将腾讯cos的注册信息配置为自己的。

package com.zyq.controller;

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.*;
import com.qcloud.cos.region.Region;
import com.zyq.util.COSBean;
import com.zyq.util.COSClientUtil;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import org.springframework.beans.factory.annotation.Autowired;
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.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.util.Date;

@Controller
public class ImgController {
    @Autowired
    private COSBean cosBean;

    //流上传
    @RequestMapping(value = "/img1",method = RequestMethod.POST)
    @ResponseBody
    public Object uploadImg1(@RequestParam("multipartFile") MultipartFile multipartFile){
        // 1 初始化用户身份信息(secretId, secretKey)
        COSCredentials cred = new BasicCOSCredentials(cosBean.getSecretId(), cosBean.getSecretKey());
        // 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        ClientConfig clientConfig = new ClientConfig(new Region(cosBean.getReginName()));
        // 3 生成cos客户端
        COSClient cosClient = new COSClient(cred, clientConfig);

        InputStream inputStream = null;
        try {
            inputStream = multipartFile.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("从multipartFile中获取文件流失败");
        }

        ObjectMetadata objectMetadata = new ObjectMetadata();
        // 设置输入流长度为
        try {
            objectMetadata.setContentLength(inputStream.available());
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("设置输入流长度异常");
        }
        objectMetadata.setContentType("image/jpeg");

        //调用腾讯cos上传流上传
        String eTag = null;
        try {
            PutObjectResult putObjectResult = cosClient.putObject(cosBean.getCosBucketName(), "img1.jpg",inputStream, objectMetadata);
            eTag = putObjectResult.getETag();
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("调用腾讯cos上传流上传异常");
        }
        System.out.println(eTag);

        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        cosClient.shutdown();

        if (eTag!=null&&eTag.length()>0){
            return "0";
        }
        return "1";
    }

    //文件上传
    @RequestMapping(value = "/img2",method = RequestMethod.POST)
    @ResponseBody
    public Object uploadImg2(@RequestParam("multipartFile") MultipartFile multipartFile, HttpServletRequest httpServletRequest){
        // 1 初始化用户身份信息(secretId, secretKey)
        COSCredentials cred = new BasicCOSCredentials(cosBean.getSecretId(), cosBean.getSecretKey());
        // 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        ClientConfig clientConfig = new ClientConfig(new Region(cosBean.getReginName()));
        // 3 生成cos客户端
        COSClient cosClient = new COSClient(cred, clientConfig);

        //获取项目所在绝对路径,并创建文件目录
        String path = httpServletRequest.getSession().getServletContext().getRealPath("/headPhoto/upload/");
        String suffix = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(".")+1);
        String fileName = "test."+suffix;
        File file = new File(path,fileName);
        if(!file.exists()){
            file.mkdirs();
        }

        //将multipartFile转换为file
        try {
            multipartFile.transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("multipartFile转换为file异常,失败");
        }

        //图片进行处理,缩放、水印等等
        try {
            String bathPath = httpServletRequest.getSession().getServletContext().getRealPath("/img");
            Thumbnails.of(file.getPath()).
                    //scalingMode(ScalingMode.BICUBIC).
                            scale(0.8)// 图片缩放80%
                    .watermark(Positions.BOTTOM_LEFT, ImageIO.read(new File(bathPath+"/wartermarkFile.png")),0.5f)
                    .toFile(path+"img2.jpg");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("上传的图片处理时发生异常");
        }

        //图片上传
        File localFile = new File(path+"img2.jpg");
        String etag=null;
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(cosBean.getCosBucketName(),"img2.jpg",localFile);
            // 设置存储类型, 默认是标准(Standard), 低频(standard_ia)
            putObjectRequest.setStorageClass(StorageClass.Standard_IA);
            PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
            etag = putObjectResult.getETag();
        }catch (Exception e){
            System.out.println("上传头像至腾讯cos发生异常,失败");
            e.printStackTrace();
        }
        file.delete();
        localFile.delete();

        URL url = cosClient.generatePresignedUrl(cosBean.getCosBucketName(),"img2.jpg",new Date(System.currentTimeMillis()+30*60*1000L));
        System.out.println(etag);
        System.out.println(url.toString());

        cosClient.shutdown();
        if (etag!=null&&etag.length()>0){
            return "0";
        }
        return "1";
    }

    //从腾讯对象存储cos获取头像
    @RequestMapping("/img1/view")
    public void getHeadPhoto(String key, HttpServletResponse response) throws IOException {

        // 1 初始化用户身份信息(secretId, secretKey)
        COSCredentials cred = new BasicCOSCredentials(cosBean.getSecretId(), cosBean.getSecretKey());
        // 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        ClientConfig clientConfig = new ClientConfig(new Region(cosBean.getReginName()));
        // 3 生成cos客户端
        COSClient cosClient = new COSClient(cred, clientConfig);

        //重置response
        response.reset();
        //设置contenttype
        response.setContentType("image/jpeg");
        COSObjectInputStream cosObjectInputStream = null;
        try {
            GetObjectRequest getObjectRequest = new GetObjectRequest(cosBean.getCosBucketName(),key);
            COSObject cosObject = cosClient.getObject(getObjectRequest);
            cosObjectInputStream = cosObject.getObjectContent();
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("调用腾讯cos获取文件流异常,失败");
        }

        //输入缓冲流
        BufferedInputStream bis = new BufferedInputStream(cosObjectInputStream);
        //得到输出流
        OutputStream outputStream = response.getOutputStream();
        //输出缓冲流
        BufferedOutputStream bos = new BufferedOutputStream(outputStream);
        // 缓冲字节数
        byte data[] = new byte[4096];
        int size = bis.read(data);
        while (size != -1) {
            bos.write(data, 0, size);
            size = bis.read(data);
        }

        bos.flush();
        bos.close();
        outputStream.close();
        bis.close();
        cosObjectInputStream.close();

        cosClient.shutdown();
    }
}

五、扩展思考

     1.可不可以通过字符流进行图片、视频等文件的传输?

       不能,计算机中的所有信息都是以二进制形式进行的存储(1010)图片中的也都是,字符流读取二进制文件的时候自动对这些二进制按照码表进行了编码处理,但是图片本来就是二进制文件,不需要进行编码。有一些巧合在码表中有对应,就可以处理,并不是所有的二进制都可以找到对应的。信息就会丢失。

     2.如何对上传的图片进行压缩、添加水印?

     利用Thumbnailator jar包,Thumbnailator是一个用java生成高质量缩略图的第三方库,可以用来生成缩率图、添加水印、图片旋转、图片大小缩放和.图片压缩等。

 六、参考文献

     https://cloud.tencent.com/document/product/436/12263

     https://blog.csdn.net/hanchao5272/article/details/79261312

     https://blog.csdn.net/lcj_star/article/details/76637931

      https://blog.csdn.net/weixin_38023551/article/details/78318532 

      https://blog.csdn.net/hanchao5272/article/details/79261312

七、更多讨论

     1.腾讯cos如何设置防盗链?

     为了避免恶意程序使用资源 URL 盗刷公网流量或使用恶意手法盗用资源,给用户带来不必要的损失。腾讯云对象存储支持防盗链配置通过控制台的防盗链设置配置黑/白名单,来进行安全防护。

     详见链接:https://cloud.tencent.com/document/product/436/13319

     2.如何处理文件名是中文? 

     (1)对于中文,一般我们会在web.xml最前面配置如下所示过滤器;

<!-- 配置过滤器, 设置编码为UTF-8 -->
    <filter>
        <filter-name>CharacterFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

   (2)如何还有个别中文乱码,我们可以针对某个字符串做如下处理转换编码格式为中文;

URLEncoder.encode("相关字符串","utf-8");

   3.表单图片上传怎么做?

     1) 表单的提交方式 :"method=post"

     2) 表单的类型 :enctype="multipart/form-data"

     3) 上传表单的文件项:<input type="file" name="xx" /> //其中名字是必须要的

八、视频教程

https://v.qq.com/x/page/b0726738ptc.html

快点加入我们吧:http://www.jnshu.com/login/1/23284132

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值