移动端 H5 拍照 从手机选择图片,移动端预览,图片压缩,图片预览,再上传服务器

摘要:
前言:最近,该公司的项目正在进行全网营销,需要对不是微信浏览器的wap站进行修订。其中一项涉及的技术是使用H5选择手机相册中的图片,或拍摄照片,然后压缩获得的图片并上传。这个功能模块主要有五个难点:1.手机很难通过js的img对象获取相册的图片文件、照片的图片文件和图片对象。

前言:最近公司的项目在做全网营销,要做非微信浏览器的wap 站 的改版,其中涉及到的一点技术就是采用H5 选择手机相册中的图片,或者拍照,再将获取的图片进行压缩之后上传。

这个功能模块主要有这5点比较难:

  1手机获取相册的图片文件,拍照的图片文件,通过js 的自带的img对象,获取图片对象。  

  2.图片的压缩,采用canvas 画布进行压缩图片,图片的质量通过参数指定大小,数值区间在0.1-0.9之间,数值越小压缩的比例越小

  3.图片的预览,将canvas画布生成的图片经过旋转平移到预览区域

  4.图片的删除和上传

  5.图片的存储

(一):h5 获取手机的图片

  这是图片上传的页面,其中包含了:预览大图的插件smartphoto,修正ios获取图片旋转的插件,正在加载中效果的插件。(因为项目的框架使用的sgform js 提交表单,也可以用自己的form 表单提交)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript">
    var _speedMark = new Date();
</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<meta content="" name="keywords"/>
        <meta content="" name="description"/>
<title>上传图片页面</title>
        <link rel="stylesheet" type="text/css" href="/css/healthRecords.css" />
        <!-- 查看大图的css -->
        <link rel="stylesheet" href="/css/smartphoto.css" />
        <!-- 查看大图的js -->
        <script type="text/javascript" src="/js/jquery-smartphoto.min.js" ></script>
        <script src="/js/bootstrap.min.js" type="text/javascript" charset="utf-8"></script>
        <!-- form 表单提交 -->
        <script type="text/javascript" src="/js/jquery.sgfmform.js"></script>
        <!-- 引用核心层插件 -->
        <script type="text/javascript" src="/js/zyFile.js"></script>
        <!-- 引用控制层插件 -->
        <script type="text/javascript" src="/js/zyUpload.js"></script>
        <!-- 修正ios图片旋转 -->
        <script type="text/javascript" src="/js/exif.js"></script>
        <!-- 图片正在加载中效果 -->
        <link rel="stylesheet" type="text/css" href="/css/loading/load.css" media="all">
        <script type="text/javascript" src="/css/loading/load-min.js"></script>
</head>
<body>
<body >
<!-- form 表单需要提交的数据,可以包含基本数据,和图片数据 -->
<form id="addExmInfo" method="post" enctype="application/x-www-form-urlencoded">
    <div class="main" style="margin-bottom: 0;padding-bottom: 0;">
            <ul class="write">    
                <li class="clearfix"  onclick="openCalendar();">
                    <span>提交人姓名</span>
                    <img src="/images/main-right.png" />
                    <input style="display:block;" value="" id="chooseDate" name="tijianTime" onfocus="this.blur()">
                </li>
            </ul>
        </div>
        <div class="main" id="imageMain" style="border-bottom: 50px solid #f7f9fa;">
            <div class="uploading" style="margin-top: 0;" id="uploadbtn" >
                <img src="/images/Upload_pic_icon.png" />
                <p class="uploadingTop">上传报告图片(手机上传)</p>
                <p class="uploadingBottom">注:请确保图片上文字清晰可见</p>
            </div>
            <!-- 图片预览区 -->
            <div id="wx_chooseimg" class="imgView"></div>
        </div>
        <!-- 浏览器类型:微信浏览器或者非微信浏览器 -->
        <input value="" type="hidden" id="agentType" name="agentType"/>
        <!-- 删除的图片id -->
        <input type="hidden" id="delIds" name="delIds"/>
        
        <input type="button" id="submitButton" value="保存"  class="btn btn-block main-btn save" />
</form>
        
        <!-- 真正触发获取手机相册的元素 -->
         <input id="fileImage" style="display:none;" type="file" accept="image/*"  size="30" name="imgSelected" multiple>
         <input id="state" type="hidden" />    
         <!-- 图片加载中效果 -->       
         <div id="test_mask_2" class="test_mask"></div>
</body>
<script type="text/javascript">
$(document).ready(function () {
    // 初始化图片插件
    $("#addExmInfo").zyUpload({
        width            :   "1000px",                 // 宽度
        height           :   "500px",                 // 宽度
        itemWidth        :   "120px",                 // 文件项的宽度
        itemHeight       :   "100px",                 // 文件项的高度
        url              :   "/core/recordExplain.upReportInfoWeb.do",  // 上传文件的路径
        multiple         :   true,                    // 是否可以多个文件上传
        dragDrop         :   true,                    // 是否可以拖动上传文件
        del              :   true,                    // 是否可以删除文件
        finishDel        :   false,                    // 是否在上传文件完成后删除预览
        /* 外部获得的回调接口 */
        onSelect: function(files, allFiles){                    // 选择文件的回调方法
        
        },
        onDelete: function(file, surplusFiles){                     // 删除一个文件的回调方法
            console.info(file);
        },
        onSuccess: function(file){                    // 文件上传成功的回调方法
        },
        onFailure: function(file){                    // 文件上传失败的回调方法
        },
        onComplete: function(responseInfo){           // 上传完成的回调方法
        }
    });
    

      $(".img_viwer").smartPhoto({
            resizeStyle: 'fit'
        });
    
      /* 这是form表单提交的js ,直接用form表单提交,不用这个js也可 */
    $("#addExmInfo").sgfmform({
         ajaxurl     : "/core/recordExplain.upReportInfoWeb.do",  
         tiptype     : 1,
         submittype  : 2,
         callback    : function(data,url){
             if(data.returncode == 0){
                  alert("图片上传成功");
                 
             }else{
                 alert("图片上传失败");
             }
             
            $("#submitButton").attr('disabled',false);  
             $("#submitButton").css("background-color","#05A3FF");
         }
    });
    
});






/* 图片删除绑定点击事件 */
function funBindDelEvent(index) {
    if ($(".file_del").length > 0) {
            confirmMsg("确认删除图片?",function(){
                ZYFILE.funDeleteFile(parseInt(index), true);
            });
      
    }
};

/* 图片正在加载中 */
function mask_element_continuious() {
    $.mask_element('#test_mask_2',3000);
}
    
</script>
</html>

(二)两个核心的图片上传的js

zyFile.js 这个js 包含图片文件的获取,图片的上传

/*
 * 
*/
var ZYFILE = {
        fileInput : "#fileImage",             // 选择文件按钮dom对象
        uploadInput : $("#submitButton").get(0),           // 上传文件按钮dom对象
        dragDrop: null,                  //拖拽敏感区域
        url : null,                        // 上传action路径
        uploadFile : [],                // 需要上传的文件数组
        lastUploadFile : [],          // 上一次选择的文件数组,方便继续上传使用
        perUploadFile : [],           // 存放永久的文件数组,方便删除使用
        fileNum : 0,                  // 代表文件总个数,因为涉及到继续添加,所以下一次添加需要在它的基础上添加索引
        /* 提供给外部的接口 */
        filterFile : function(files){ // 提供给外部的过滤文件格式等的接口,外部需要把过滤后的文件返回
        
        },
        onDelete : function(file, files){            // 提供给外部获取删除的单个文件,供外部实现删除效果  file:当前删除的文件  files:删除之后的文件
            
        },
        onProgress : function(file, loaded, total){  // 提供给外部获取单个文件的上传进度,供外部实现上传进度效果
            
        },
        onSuccess : function(file, responseInfo){    // 提供给外部获取单个文件上传成功,供外部实现成功效果
            
        },
        onFailure : function(file, responseInfo){    // 提供给外部获取单个文件上传失败,供外部实现失败效果
        
        },
        onComplete : function(responseInfo){         // 提供给外部获取全部文件上传完成,供外部实现完成效果
            
        },
        
        // 3.将获取的图片数据加入到文件数组中,注意下面的else 的判断,这个判断是因为ios 拍照每次获取的图片名称都是一样的,如果根据图片名称来区分是否是同一张图片将会失败。相同的图片名称只会显示一张,所以这里else 解决了ios 拍照不能拍多次的问题
        funGetFiles : function(e){ 
            var self = this;
            /* 从事件中获取选中的所有文件*/
            var files = e.target.files || e.dataTransfer.files;
            self.lastUploadFile = this.uploadFile;
            this.uploadFile = this.uploadFile.concat(this.filterFile(files));  //将过滤后的文件重新组装
            var tmpFiles = [];
            /*因为jquery的inArray方法无法对object数组进行判断是否存在于,所以只能提取名称进行判断*/
            var lArr = [];  // 之前文件的名称数组
            var uArr = [];  // 现在文件的名称数组
            $.each(self.lastUploadFile, function(k, v){
                lArr.push(v.name);
            });
            $.each(self.uploadFile, function(k, v){
                uArr.push(v.name);
            });
            $.each(uArr, function(k, v){
                // 获得当前选择的每一个文件   判断当前这一个文件是否存在于之前的文件当中
                if($.inArray(v, lArr) < 0){  // 不存在
                    tmpFiles.push(self.uploadFile[k]);
                }else{
                    /* 
                     * 功能:因为ios每次拍照返回的文件名称都是image.jpg 所以只用文件名去重的方式会导致大于第二次的拍照的图片不能存放到uploadFile 数组中,
                     *         预览的时候就是没有第二次及以上的拍照的图片
                     * return:拍照的照片文件
                     */
                    if((v=="image.jpg")&&(k==(uArr.length-1))){
                        tmpFiles.push(self.uploadFile[k]);
                    }
                }
            });
                this.uploadFile = tmpFiles;
            // 调用对文件处理的方法
            this.funDealtFiles();
            return true;
        },
        // 处理过滤后的文件,给每个文件设置下标
        funDealtFiles : function(){
            var self = this;
            // 目前是遍历所有的文件,给每个文件增加唯一索引值
            $.each(this.uploadFile, function(k, v){
                // 因为涉及到继续添加,所以下一次添加需要在总个数的基础上添加
                v.index = self.fileNum;
                // 添加一个之后自增
                self.fileNum++;
            });
            // 先把当前选中的文件保存备份
            var selectFile = this.uploadFile;  
            // 要把全部的文件都保存下来,因为删除所使用的下标是全局的变量
            this.perUploadFile = this.perUploadFile.concat(this.uploadFile);
            // 合并下上传的文件
            this.uploadFile = this.lastUploadFile.concat(this.uploadFile);
            // 4.这里调用下面zyUpload.js 的onselect 方法,对图片进行处理
            this.onSelect(selectFile, this.uploadFile);
            return this;
        },
        // 处理需要删除的文件  isCb代表是否回调onDelete方法  
        // 因为上传完成并不希望在页面上删除div,但是单独点击删除的时候需要删除div   所以用isCb做判断
        funDeleteFile : function(delFileIndex, isCb){
            var self = this;  // 在each中this指向没个v  所以先将this保留
            
            var tmpFile = [];  // 用来替换的文件数组
            // 合并下上传的文件
            var delFile = this.perUploadFile[delFileIndex];
            // 目前是遍历所有的文件,对比每个文件  删除
            $.each(this.uploadFile, function(k, v){
                if(delFile != v){
                    // 如果不是删除的那个文件 就放到临时数组中
                    tmpFile.push(v);
                }else{
                    
                }
            });
            this.uploadFile = tmpFile;
            if(isCb){  // 执行回调
                // 回调删除方法,供外部进行删除效果的实现
                self.onDelete(delFile, this.uploadFile);
            }
            return true;
        },
        // 11.图片上传的方法
        funUploadFiles : function(){
                 if((ZYFILE.funReturnNeedFiles().length == 0)&&($("#wx_chooseimg:has(img)" ).length==0)){
                    alertMsg({"type" : 3, "content" : "请上传图片", "close" : true, "timeout" : 3000}, function(){});
                }else{
                    //点击保存之后按钮灰掉
                    $("#submitButton").css("background-color","gray");
                    $("#submitButton").attr('disabled',true);  
                    $("#addExmInfo").submit();    
                }
        },
        // 返回需要上传的文件
        funReturnNeedFiles : function(){
            return this.uploadFile;
        },
        
        // 初始化
        init : function(){                  // 初始化方法,在此给选择、上传按钮绑定事件
            var self = this;                  // 克隆一个自身
            this.userAgent();                 // 给元素添加属性
                    
            // 1.点击选择图片按钮会先触发这里的监听,点击获取图片将从这里开始
            if(self.fileInput){
                this.fileInput.addEventListener("change", function(e) {
          2.将获取的file文件交个funGetFileses(e)这个方法进行下一步的处理,e 包含获取的图片信息和其他数据 self.funGetFiles(e); },
false); } }, /*判断是android 还是 ios android 要加capture="camera" ios 不用加 ; 1 代表android 2 代表ios*/ userAgent:function(){ var agentFlag=1; var u = navigator.userAgent; var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端 var isiOS = !!u.match(/(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端 if(isAndroid){ //$(this.fileInput).attr("capture","camera"); $("#agentType").val("isAndroid") }else if(isiOS){ agentFlag=2; $("#agentType").val("isIos") }else{ } var ua = window.navigator.userAgent.toLowerCase(); if (ua.match(/MicroMessenger/i) == 'micromessenger') { //alert("微信"); } else { // alert("非微信"); } return agentFlag; } };

zyUpload.js 这个js是图片预览,压缩的核心js,首先要整理出这个js 的逻辑比较有点困难,对于那些在js 面向对象编程方面了解不多的童鞋,不过也没多大问题多看几遍就知道了。

这个js 首先要知道这几点:

  1.$.fn 这个的意思,这是jquery 的扩展方法,当给jquery 添加这个扩展方法的时候就可以使用$操作符对这个js 的方法进行调用。

  2. js 的函数回调,函数回调分为同步回到和异步回调

  3.returnthis.each(fucntion(){})  这个的方法的作用是为了链式操作   

  4. para = $.extend(defaults, options); 这个方法是增强,就是将默认的和特定的参数进行结合,可以理解为韦恩图中的并集     

/* 代码整理:懒人之家 www.lanrenzhijia.com */
(function($, undefined) {
    $.fn.zyUpload = function(options, param) {
        return this.each(function() {
                    var para = {}; // 保留参数
                    var self = this; // 保存组件对象
                    var base64Img = []; // 创建一个数组保存base64 编码的图片

                    var defaults = {
                        width : "700px", // 宽度
                        height : "400px", // 宽度
                        itemWidth : "140px", // 文件项的宽度
                        itemHeight : "120px", // 文件项的高度
                        multiple : true, // 是否可以多个文件上传
                        dragDrop : true, // 是否可以拖动上传文件
                        del : true, // 是否可以删除文件
                        finishDel : false, // 是否在上传文件完成后删除预览
                        minLimitNum : 2 * 1024 * 1024, // 当文件的大小小于这个值时,不压缩
                        // 单位(bit)
                        isResize : true, // 是否压缩文件
                        base64ImgUrl : [], // 经过canvas 压缩过的图片地址,组成的图片数组
                        /* 提供给外部的接口方法 */
                        onSelect : function(selectFiles, files) {
                        },// 选择文件的回调方法 selectFile:当前选中的文件 allFiles:还没上传的全部文件
                        onDelete : function(file, files) {
                        }, // 删除一个文件的回调方法 file:当前删除的文件 files:删除之后的文件
                        onSuccess : function(file) {
                        }, // 文件上传成功的回调方法
                        onFailure : function(file) {
                        }, // 文件上传失败的回调方法
                        onComplete : function(responseInfo) {
                        }, // 上传完成的回调方法
                    };

                    para = $.extend(defaults, options);

                    this.init = function() {
                        this.addEvent();
                        this.createCorePlug(); // 调用核心js
                    };

                    /**
                     * 识别是否是手机浏览器 对选择文件夹按钮添加属性
                     */
                    this.findIsPhone = function() {
                        var userAgentInfo = navigator.userAgent;
                    };

                    /*
                     * 点击图片进行预览
                     */
                    this.zoomOutImage = function(imgUrl) {

                    };

                    /**
                     * 功能:显示统计信息和绑定继续上传和上传按钮的点击事件 参数: 无 返回: 无
                     */
                    this.funSetStatusInfo = function(files) {
                        var size = 0;
                        var num = files.length;
                        $.each(files, function(k, v) {
                            // 计算得到文件总大小
                            size += v.size;
                        });

                        // 转化为kb和MB格式。文件的名字、大小、类型都是可以现实出来。
                        if (size > 1024 * 1024) {
                            size = (Math.round(size * 100 / (1024 * 1024)) / 100)
                                    .toString()
                                    + 'MB';
                        } else {
                            size = (Math.round(size * 100 / 1024) / 100)
                                    .toString()
                                    + 'KB';
                        }
                        
                       alert("获取图片的总大小=="+size ) 
                    };

                    /**
                     * 功能:过滤上传的文件格式 参数: files 本次选择的文件 返回: 通过的文件
                     */
                    this.funFilterEligibleFile = function(files) {
                        var arrFiles = []; // 替换的文件数组
                        for (var i = 0, file; file = files[i]; i++) {
                            if (file.size >= 51200000) {
                                alert('您选择的"' + file.name + '"图片大小过大');
                            } else {
                                // 在这里需要判断当前所有文件中
                                var fileExt = file.name.substr(
                                        file.name.lastIndexOf(".")).toLowerCase();// 获得文件后缀名
                                if (fileExt == ".png" || fileExt == ".gif"
                                        || fileExt == ".jpg"
                                        || fileExt == ".jpeg") {arrFiles.push(file);// 如果文件是图片格式,那么就放入文件的数组
                                } else {
                                    alert("您上传的图片格式不正确,请重新选择!");
                                }
                            }
                        }
                        return arrFiles;
                    };

                    /*
                     * 功能:对图片进行压缩
                     * 参数:img 是从文件系统中获取的image对象
                     *         max_width 预览的最大宽度,
                     *         max_height 预览的最大高度
                     * 返回值: src 需要填充的地址
                     */
                    function resizeMe(img, max_width, max_height) {
                        // 获取照片的拍摄方向
                        var orient = getPhotoOrientation(img);
                        //当检测图片的方向为6 的时候说明图片方向右(exif.js 这么定义的),开始旋转图片
                        if (orient == 6) {
                            var canvas = document.createElement('canvas');
                            var width = img.width;
                            var height = img.height;
                            var exWith;
                            var exHeight;
                            canvas.width = height;
                            canvas.height = width;
                            var ctx = canvas.getContext("2d");
                            ctx.save();//保存状态
                            ctx.rotate(90 * Math.PI / 180);//把画布旋转90度
                            //ctx.translate(0, height);  //平移
                            // 执行Canvas的drawImage语句
                            ctx.drawImage(img, 0, -height, width,height);//把图片绘制在画布,
                            //alert(getRatio(img))
                            ctx.restore();//恢复状态                     
                            return canvas.toDataURL("image/jpeg", 0.1);
                        } else {
                            var canvas = document.createElement('canvas');
                            var width = img.width;
                            var height = img.height;
                            canvas.width = width;
                            canvas.height = height;
                            var ctx = canvas.getContext("2d");
                            ctx.drawImage(img, 0, 0, width, height);
                            //alert("比例=="+getRatio(img));
                            return canvas.toDataURL("image/jpeg", 0.2);
                        }
                        
                    };
                    
                    
                    function getRatio(img) {
                        alert("kaishi")
                    /*    if(/png$/i.test(img.src)) {
                            alert(2);
                            return 1;
                        }*/
                        var iw = img.naturalWidth, ih = img.naturalHeight;
                        var canvas = document.createElement('canvas');
                        canvas.width = 1;
                        canvas.height = ih;
                        var ctx = canvas.getContext('2d');
                        ctx.drawImage(img, 0, 0);
                        var data = ctx.getImageData(0, 0, 1, ih).data;
                        var sy = 0;
                        var ey = ih;
                        var py = ih;
                        while (py > sy) {
                            var alpha = data[(py - 1) * 4 + 3];
                            if (alpha === 0) {
                                ey = py;
                            } else {
                                sy = py;
                            }
                            py = (ey + sy) >> 1;
                        }
                        var ratio = (py / ih);
                        return (ratio===0)?1:ratio;
                    }
                    

                    /*
                     * 功能:获取照片的元信息(拍摄方向,来自exif.js 的api)
                     * 返回值:方向的枚举值 6 代表ios 返回的图片方向
                     */ 
                    function getPhotoOrientation(img) {
                        var orient;
                        EXIF.getData(img, function() {
                            orient = EXIF.getTag(this, 'Orientation');
                        });
                        return orient;
                    }
                
                    /**
                     * 功能: 处理参数和格式上的预览html 参数: files 本次选择的文件 返回: 预览的html
                     */
                    this.funDisposePreviewHtml = function(file, img) {
/*                        alert(img.substring((img.length-100),img.length));
*/                        var html = "";
                        // 处理不同类型文件代表的图标
                        var fileImgSrc = "control/images/fileType/";
                        if (file.type.indexOf("rar") > 0) {
                            fileImgSrc = fileImgSrc + "rar.png";
                        } else if (file.type.indexOf("zip") > 0) {
                            fileImgSrc = fileImgSrc + "zip.png";
                        } else if (file.type.indexOf("text") > 0) {
                            fileImgSrc = fileImgSrc + "txt.png";
                        } else {
                            fileImgSrc = fileImgSrc + "file.png";
                        }
                        var tempImgUrl=img.replace("data:image/jpeg;base64,", "");
                            var html = "<i   id='uploadList_"+file.index+"'>" ;
                            // html +=         "<a   data-caption='"+file.index+"' data-id='"+file.index+"' data-group='0'  href='https://tool.4xseo.com/article/283720.html"+img+"'>" ;
                             html +=         "<img id='uploadImage_" + file.index + "' src='https://tool.4xseo.com/article/283720.html"+img+"'   />" ;
                            // html +=         "</a>";
                             html +=         "<img id='deleteBtn_" + file.index + "'  data-index='" + file.index + "' onclick='funBindDelEvent("+file.index+")' src='http://t.zoukankan.com/images/health/delete_icon.png'  />" ;
                             html += '        <input name="upload_image"   value="'+tempImgUrl+'">';
                             html +=   "</i>";
                        return html;
                    };
                    /**
                     * 功能:调用核心插件 参数: 无 返回: 无
                     */
                    this.createCorePlug = function() {
                        $("#addExmInfo").attr("action", para.url);
                        var params = {
                            fileInput : $("#fileImage").get(0),
                            uploadInput : $("#submitButton").get(0),
                            url : $("#addExmInfo").attr("action"),

                            filterFile : function(files) {
                                // 过滤合格的文件
                                return self.funFilterEligibleFile(files);
                            },
                //5.(
紧接着zyFile.js 的流程)获取的图片在这里进行解析,获取image对象,调用图片压缩方法,调用添加预览图片的方法
                            onSelect : function(selectFiles, allFiles) {
                                para.onSelect(selectFiles, allFiles); // 回调方法
                                var html = '', i = 0;
                                // 组织预览html
                                var funDealtPreviewHtml = function() {
                                    file = selectFiles[i];
                                    mask_element_continuious();
                                    if (file) {
                      //6.通过FileReader 这个js的原生对象,获取图片对象,FileReader 获取的图片数据是经过base64位编码的图片
var reader = new FileReader() reader.onload = function(e) { // 7.创建一个image对象 var img = new Image;
                          //8.接收reader中获取的图片数据,传递给iamge对象 img.src
= reader.result; var dataUrl; img.onload = function() {
                            //9.调用resizeMe 的方法进行图片压缩,图片压缩采用canvase画布,用canvas 自带的图片压缩方法进行压缩,这里的图片平移和旋转将会直接影响你是否能成功的预览到图片 dataUrl
= resizeMe(img, 1000,1000); // 10.将获取的图片在预览区域进行展示 html += self.funDisposePreviewHtml(file, dataUrl); i++; // 再接着调用此方法递归组成可以预览的html funDealtPreviewHtml(); } } reader.readAsDataURL(file); } else { // 走到这里说明文件html已经组织完毕,要把html添加到预览区 funAppendPreviewHtml(html);
                       //11.图片压缩是需要一点时间的,这里是关闭loading遮罩 $.mask_close_all(); } };
// 添加预览html var funAppendPreviewHtml = function(html) { $("#wx_chooseimg").append(html); }; funDealtPreviewHtml(); // 显示转化后的统计信息 self.funSetStatusInfo(ZYFILE.funReturnNeedFiles()); }, onDelete : function(file, files) { // 移除效果 $("#uploadList_" + file.index).fadeOut(); //并且删除节点 $("#uploadList_" + file.index).remove(); }, onComplete : function(response) { } }; ZYFILE = $.extend(ZYFILE, params); ZYFILE.init(); }; /*// 绑定删除按钮事件 this.funBindDelEvent = function(index) { if ($(".file_del").length > 0) { alert("删除"); ZYFILE.funDeleteFile(parseInt(index), true); } };*/ /** * 功能:绑定事件 参数: 无 返回: 无 */ this.addEvent = function() { // 如果快捷添加文件按钮存在 if ($("#uploadbtn").length > 0) { // 绑定选择事件 $("#uploadbtn").bind("click", function(e) { ZYFILE.fileInput.click(); }); } //上传按钮绑定点击事件 if ($("#submitButton").length > 0) { // 绑定选择事件 $("#submitButton").bind("click", function(e) { ZYFILE.funUploadFiles(); }); } }; // 初始化上传控制层插件 this.init(); }); }; })(jQuery);

(三)java 后台接受数据存储到数据库和磁盘中

前台传递过来的数据是form 表单进行提交的,图片也包含在form表单中,提交的图片是经过base64 编码的图片,接受数据后首先要解码,再往磁盘中存数据

/*
     * 上传图片的action 的方法
     */
    public String uploadImg(){
        JsonResponseResult result=null;
        try{
            String agentType=super.getRequest().getParameter("agentType");
            
            String[] files=super.getRequest().getParameterValues("upload_image");  //图片用values 进行接受
            HashMap<String, Object> param=new HashMap<>();
            param.put("imgs", files); 
            if(agentType!=null){
                if(agentType.equals("isIos")){ //android
                    Thread.sleep(3000);  //request 接受数据的时候做一个延时,保证数据能接受完
                }
            }
//保存图片的service方法
boolean flag=recordExplainService.addUploadImg(param); //TODO 这个地方的异常有问题,稍后再改 if(flag==true){ result=JsonResponseResult.createSuccess("添加图片成功"); }else{ result=JsonResponseResult.createFalied("服务器繁忙,请稍后重试!"); } }catch(AppException app){ app.printStackTrace(); logger.info("RecordExplainAction---->upReportHosInfo"); result=JsonResponseResult.createFalied("保存图片失败!请联系管理员"); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); logger.info("RecordExplainAction---->upReportHosInfo"); result=JsonResponseResult.createFalied("保存图片失败!请联系管理员"); } super.jsonResult = JSONObject.fromObject(result).toString(); return BaseAction.JSON; }

impl

    /**
     * @throws InterruptedException 
     * @see 插入图片
     */
    @Override
    public boolean addUploadImg(HashMap<String, Object> params) throws InterruptedException {
        boolean flag = false;
      
        String[] files=(String[]) params.get("imgs");
        params.remove("imgs");
        Integer count=0;
        List<HashMap<String, Object>> imgList = new ArrayList<>();
        for (int i = 0; i < files.length; i++) {
            String filename = "web_"+System.currentTimeMillis() + ".jpeg";
  
            imgList.add(img);
            //前台传递过来的图片是经过base64 加密的,在这里进行解密
            //String tempUrl=files[i].replace("data:image/jpg;base64,", "");
            byte[] buffer=AESUtilHTBX.base64Decode(files[i]);
            HashMap<String, Object> hashMap=new HashMap<>();  //保存图片到文件系统中的map
            //将解密出来的字节数组填充到输入流中
            InputStream fis = new ByteArrayInputStream(buffer);
            hashMap.put("fileName", filename);
            hashMap.put("pathType", 6);
            hashMap.put("inputstr", fis);
        
            Map<String, Object> map=this.doUploadFile("1", hashMap);  //公用的图片上传的方法,发送一个post请求
            if(map.get("flag").equals("1")){
                ++count;    
            }
        }
        if(count==files.length){
            //将基本数据持久化到数据库中
            flag=true;
        }
        return flag;
    }

base64 解码方法

    /**
         * base64解码
         * 
         * @param base64Code
         * 待解码的base64字符串
         * @return 解码后的字节数组
         * @throws Exception
         */
        public static byte[] base64Decode(String base64Str) {
            return Base64.decodeBase64(base64Str);
        }

往磁盘中插入图片

    /**
     * 上传图片
     * @return
     * @throws IOException
     */
    public String doPostFile() throws IOException {
        JsonResponseResult result = null;
        PrintWriter out = super.getResponse().getWriter();
        try {

            String savaPath = "";
            String pathType = super.getRequest().getParameter("pathType");
            String fileName = super.getRequest().getParameter("fileName");
          
                    String mobile1 = super.getRequest().getParameter("mobile");
                    savaPath = propsLoader.props.getProperty("savePath") + mobile1 + "\";
            File tempFile = new File(savaPath);
            if (!tempFile.exists()) {
                tempFile.mkdirs();
            }

            ServletInputStream input = super.getRequest().getInputStream();

            // file文件流
            File outFile = null;
            FileOutputStream outStream = null;
            byte[] buffer = new byte[1024];
            int l = 0;

            outFile = new File(savaPath + fileName);
            outStream = new FileOutputStream(outFile);
            while ((l = input.read(buffer)) > 0) {
                outStream.write(buffer, 0, l);
            }
            l = 0;
            outStream.flush();
            outStream.close();
            input.close();
            
            /*if(pathType.equals("3")){
                //压缩图片
                pictureCutService.imgCut("3", fileName);
            }*/
            
            HashMap<String, String> map = new HashMap<String, String>();
            map.put("flag", "1");
            map.put("fileName", fileName);
            String jsonData = JSONObject.fromObject(map).toString();
            out.print(jsonData);

        } catch (final AppException app) {
            this.logger.error(app);
            HashMap<String, String> map = new HashMap<String, String>();
            map.put("flag", "0");
            String jsonData = JSONObject.fromObject(map).toString();
            out.print(jsonData);
            
            final String msg = this.getText(app.getMessage());
            result = JsonResponseResult.createFalied(msg);
            super.jsonResult = JSONObject.fromObject(result).toString();
        } catch (final Exception e) {
            this.logger.error(e);
            HashMap<String, String> map = new HashMap<String, String>();
            map.put("flag", "0");
            String jsonData = JSONObject.fromObject(map).toString();
            out.print(jsonData);
            
            final String msg = getText("com.sgfm.datacenter.action.order.OrderAction.exception");
            result = JsonResponseResult.createFalied(msg);
            super.jsonResult = JSONObject.fromObject(result).toString();
        }
        return BaseAction.JSON;
    }

这里的java 方法不能直接用,需要自己去结合自己的项目去写。这里只列出来几点重要处理:图片的base64 解码、通过输入输出流往磁盘中写图片文件

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE html><html lang="en"><head><script type="text/javascript">var _speedMark = new Date();</script><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /><meta content="" name="keywords"/>    <meta content="" name="description"/><title>上传图片页面</title><link rel="stylesheet" type="text/css" href="http://t.zoukankan.com/css/healthRecords.css" /><!-- 查看大图的css --><link rel="stylesheet" href="http://t.zoukankan.com/css/smartphoto.css" /><!-- 查看大图的js --><script type="text/javascript" src="http://t.zoukankan.com/js/jquery-smartphoto.min.js" ></script><script src="http://t.zoukankan.com/js/bootstrap.min.js" type="text/javascript" charset="utf-8"></script><!-- form 表单提交 --><script type="text/javascript" src="http://t.zoukankan.com/js/jquery.sgfmform.js"></script><!-- 引用核心层插件 --><script type="text/javascript" src="http://t.zoukankan.com/js/zyFile.js"></script><!-- 引用控制层插件 --><script type="text/javascript" src="http://t.zoukankan.com/js/zyUpload.js"></script><!-- 修正ios图片旋转 --><script type="text/javascript" src="http://t.zoukankan.com/js/exif.js"></script><!-- 图片正在加载中效果 --><link rel="stylesheet" type="text/css" href="http://t.zoukankan.com/css/loading/load.css" media="all"><script type="text/javascript" src="http://t.zoukankan.com/css/loading/load-min.js"></script></head><body><body ><!-- form 表单需要提交的数据,可以包含基本数据,和图片数据 --><form method="post" enctype="application/x-www-form-urlencoded"><div style="margin-bottom: 0;padding-bottom: 0;"><ul class="write"><li  onclick="openCalendar();"><span>提交人姓名</span><img src="http://t.zoukankan.com/images/main-right.png" /><input value="" name="tijianTime" onfocus="this.blur()"></li></ul></div><div style="border-bottom: 50px solid #f7f9fa;"><div ><img src="http://t.zoukankan.com/images/Upload_pic_icon.png" /><p class="uploadingTop">上传报告图片(手机上传)</p><p class="uploadingBottom">注:请确保图片上文字清晰可见</p></div><!-- 图片预览区 --><div class="imgView"></div></div><!-- 浏览器类型:微信浏览器或者非微信浏览器 --><input value="" type="hidden" name="agentType"/><!-- 删除的图片id --><input type="hidden" name="delIds"/><input type="button" value="保存"   /></form><!-- 真正触发获取手机相册的元素 --> <input type="file" accept="image/*"  size="30" name="imgSelected" multiple> <input type="hidden" /> <!-- 图片加载中效果 -->        <div class="test_mask"></div></body><script type="text/javascript">$(document).ready(function () {// 初始化图片插件$("#addExmInfo").zyUpload({width            :   "1000px",                 // 宽度height           :   "500px",                 // 宽度itemWidth        :   "120px",                 // 文件项的宽度itemHeight       :   "100px",                 // 文件项的高度url              :   "/core/recordExplain.upReportInfoWeb.do",  // 上传文件的路径multiple         :   true,                    // 是否可以多个文件上传dragDrop         :   true,                    // 是否可以拖动上传文件del              :   true,                    // 是否可以删除文件finishDel        :   false,    // 是否在上传文件完成后删除预览/* 外部获得的回调接口 */onSelect: function(files, allFiles){                    // 选择文件的回调方法},onDelete: function(file, surplusFiles){                     // 删除一个文件的回调方法console.info(file);},onSuccess: function(file){                    // 文件上传成功的回调方法},onFailure: function(file){                    // 文件上传失败的回调方法},onComplete: function(responseInfo){           // 上传完成的回调方法}});
 $(".img_viwer").smartPhoto({    resizeStyle: 'fit'    });  /* 这是form表单提交的js ,直接用form表单提交,不用这个js也可 */$("#addExmInfo").sgfmform({ ajaxurl : "/core/recordExplain.upReportInfoWeb.do",   tiptype : 1, submittype  : 2, callback    : function(data,url){ if(data.returncode == 0){ alert("图片上传成功"); }else{ alert("图片上传失败"); } $("#submitButton").attr('disabled',false);   $("#submitButton").css("background-color","#05A3FF"); }});});





/* 图片删除绑定点击事件 */function funBindDelEvent(index) {    if ($(".file_del").length > 0) {        confirmMsg("确认删除图片?",function(){                ZYFILE.funDeleteFile(parseInt(index), true);        });          }};
/* 图片正在加载中 */function mask_element_continuious() {$.mask_element('#test_mask_2',3000);}</script></html>

免责声明:文章转载自《移动端 H5 拍照 从手机选择图片,移动端预览,图片压缩,图片预览,再上传服务器》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇de4dot 脱壳工具su安装下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java导出CSV文件

阅读原文 调用类 @Test public void testWrite() throws Exception { FileOutputStream fos = new FileOutputStream("E:/cjsworkspace/cjs-excel-demo/target/abc.csv"); OutputS...

asp.net core网关Ocelot的简单介绍&amp;amp; Ocelot集成Identity认证

文章简介  Ocelot网关简介  Ocelot集成Idnetity认证处理 Ocelot网关简介 Ocelot是一个基于netcore实现的API网关,本质是一组按特定顺序排列的中间件。Ocelot内部实现了路由转发,限流,熔断,请求聚合,服务发现(集成consul,eureka等),负载均衡,认证(集成Identity)功能。 这里简单介绍下ocel...

js前台传数组,java后台接收转list,前后台用正则校验

前台,传参数时,将数组对象转换成json串,后台java收到后用 JSONArray.fromObject 转成集合。 前台js:var params = {"FileNameList": JSON.stringify(fileNames)}; 前台正则校验: var reg = /^[u4e00-u9fa5A-Za-z0-9-]{1,50}.txt$/;...

AdminLte 框架 和 requireJs 整合的问题

最近在 做一个基于 adminLte 框架的项目,在我将 require 引进项目之后,框架中的 adminlte.js 中搞的左侧边栏 就不起作用了。 刚开始以为是 各位不符合 requireJs 的书写格式,随后将 adminLTe。js 的 源码 修改为 define() 的格式,然而 当然还是没有效果。 define(['jquery'],func...

POI导出word

最近有一个项目需要用做导出word的功能,刚开始用的是poi,开始写的时候才发现poi对于word的支持真的是少的可怜,还是推荐大家用xml或者别的来做导出word,本次功能分两篇博客展现如果用需要用poi的可以看看这篇博客,欢迎补充。 替换word表格参数 动态生成行 根据word模板导出word public class WordUtil { /...

前端面试常考题:JS垃圾回收机制

摘要:众所周知,应用程序在运行过程中需要占用一定的内存空间,且在运行过后就必须将不再用到的内存释放掉,否则就会出现下图中内存的占用持续升高的情况,一方面会影响程序的运行速度,另一方面严重的话则会导致整个程序的崩溃。 众所周知,应用程序在运行过程中需要占用一定的内存空间,且在运行过后就必须将不再用到的内存释放掉,否则就会出现下图中内存的占用持续升高的情况,...