springMVC + ajaxfileupload异步上传图片预览,裁剪并保存图片

来源:互联网 发布:软件欢迎界面 素材 编辑:程序博客网 时间:2024/04/27 20:50

1、整体效果图:

2、实现原理:

(1)利用input的onchange事件异步上传图片到服务器

(2)获取上传图片的相对地址,回显到img标签中

(3)利用jcrop裁剪图片,提交给后台裁剪的起始坐标,宽度、高度

(4)后台裁剪图片并保存


3、用到的插件:

(1)JCrop图片裁剪插件

(2)异步上传图片插件:Ajaxfileupload.js

4、实现:

(1)jsp关键代码:

[html] view plaincopyprint?
  1. <fieldset>  
  2.     <legend>头像上传</legend>  
  3.     <!-- 显示图片的img -->  
  4.     <img src="" id="realPic" width="400px" height="400px" />  
  5.     <!-- 缩略图预览 -->  
  6.     <div id="preview-pane">  
  7.         <div class="preview-container">  
  8.             <img src="" width="150px" height="150px" />  
  9.         </div>  
  10.     </div>  
  11.     <div class="container">  
  12.         <!-- 打开图片控制 -->  
  13.                 <span class="btn btn-success fileinput-button">   
  14.                     <i class="icon-plus icon-white"></i>   
  15.                     <span>选择图片</span>   
  16.                     <input type="file" onchange="ajaxFileUpload()" name="realPicFile" id="realPicFile" multiple />  
  17.                 </span>  
  18.                <!--       
  19.                这种做法IE不支持,拒绝访问.                                                          
  20.                <input id="realPicFile" value="选择图片" onchange="ajaxFileUpload()" type="file" style="display: none;" name="realPicFile" />  
  21.                <a class="btn btn-success" href="javascript:selectPic();" > <i class="icon-plus icon-white"></i>  
  22.                     选择图片   
  23.                </a>  
  24.                 -->  
  25.         <!-- 上传并裁剪图片 -->  
  26.         <img src="${ctx}/images/ajax-loader.gif" id="loading" style="display: none;">    
  27.         <a class="btn btn-success" href="javascript:cutPic();"><i class="icon-picture icon-white"></i>保存头像</a>  
  28.         <!-- 获取裁剪的起始坐标和宽度、高度给后台 -->  
  29.         <form id="coords" class="coords">  
  30.             <div class="inline-labels">  
  31.                 <input type="hidden" size="4" id="x1" name="x1" />  
  32.                 <input type="hidden" size="4" id="y1" name="y1" />  
  33.                 <input type="hidden" size="4" id="x2" name="x2" />  
  34.                 <input type="hidden" size="4" id="y2" name="y2" />  
  35.                 <input type="hidden" size="4" id="w" name="w" />  
  36.                 <input type="hidden" size="4" id="h" name="h" />  
  37.             </div>  
  38.          </form>  
  39.     </div>  
  40. </fieldset>  

控制样式的CSS :

[css] view plaincopyprint?
  1. .jcrop-holder #preview-pane {  
  2.   width:156px;  
  3.   height:156px;   
  4.   displayblock;  
  5.   positionabsolute;  
  6.   /*z-index: 2000;*/  
  7.   top: 0px;  
  8.   right: -200px;  
  9.   padding6px;  
  10.   border1px rgba(0,0,0,.4solid;  
  11.   background-colorwhite;  
  12.   
  13.   -webkit-border-radius: 6px;  
  14.   -moz-border-radius: 6px;  
  15.   border-radius: 6px;  
  16.   
  17.   -webkit-box-shadow: 1px 1px 5px 2px rgba(0000.2);  
  18.   -moz-box-shadow: 1px 1px 5px 2px rgba(0000.2);  
  19.   box-shadow: 1px 1px 5px 2px rgba(0000.2);  
  20. }  
  21.   
  22. /* The Javascript code will set the aspect ratio of the crop 
  23.    area based on the size of the thumbnail preview, 
  24.    specified here */  
  25. #preview-pane .preview-container {  
  26.   width156px;  
  27.   height156px;  
  28.   overflowhidden;  
  29. }  
  30. #target-pane {  
  31.     width400px;  
  32.     height400px;  
  33. }  
  34.   
  35.   
  36. .fileinput-button {  
  37.   positionrelative;  
  38.   overflowhidden;  
  39. }  
  40. .fileinput-button input {  
  41.   positionabsolute;  
  42.   top: 0;  
  43.   right: 0;  
  44.   margin0;  
  45.   opacity: 0;  
  46.   filter: alpha(opacity=0);  
  47.   transform: translate(-300px0) scale(4);  
  48.   font-size23px;  
  49.   directionltr;  
  50.   cursorpointer;  
  51. }  

注意fileinput-button这个样式,本人对css不熟悉,所以这个代码是从jquery-file-upload插件中拷贝过来的,大概的意思是将file的input放到按钮上,置为透明,这样就能够兼容IE,否则如果隐藏input,而触发它的click事件,IE认为这样做不安全,报拒绝访问的错误

(2)、javascript关键代码:

[javascript] view plaincopyprint?
  1. //Create variables (in this scope) to hold the API and image size  
  2. var jcrop_api, boundx, boundy, path;  
  3. /** 
  4.  * 更新缩略图,实现原理:根据原图框选的内容,显示到缩略图上,而缩略图也是原图是进行了放大,只是超过img范围的部分被隐藏 
  5.  */  
  6. function updatePreview(c) {  
  7.     if (parseInt(c.w) > 0) {  
  8.         $('#x1').val(c.x);  
  9.         $('#y1').val(c.y);  
  10.         $('#x2').val(c.x2);  
  11.         $('#y2').val(c.y2);  
  12.         $('#w').val(c.w);  
  13.         $('#h').val(c.h);  
  14.         
  15.         var rx = xsize / c.w;  
  16.         var ry = ysize / c.h;  
  17.   
  18.         // 精确计算图片的位置  
  19.         $pimg.css({  
  20.             width : Math.round(rx * boundx) + 'px',  
  21.             height : Math.round(ry * boundy) + 'px',  
  22.             marginLeft : '-' + Math.round(rx * c.x) + 'px',  
  23.             marginTop : '-' + Math.round(ry * c.y) + 'px'  
  24.         });  
  25.     }  
  26. }  
  27.   
  28. /** 
  29.  * 异步上传图片 
  30.  * @returns {Boolean} 
  31.  */  
  32. function ajaxFileUpload() {  
  33.     $("#loading").ajaxStart(function() {  
  34.         $(this).show();  
  35.     })//开始上传文件时显示一个图片    
  36.     .ajaxComplete(function() {  
  37.         $(this).hide();  
  38.     });//文件上传完成将图片隐藏起来    
  39.   
  40.     var file = $("#realPicFile").val();  
  41.     if(!/\.(gif|jpg|jpeg|png|JPG|PNG)$/.test(file))  
  42.     {  
  43.         Error("不支持的图片格式.图片类型必须是.jpeg,jpg,png,gif格式.");  
  44.         return false;  
  45.     }  
  46.       
  47.     $.ajaxFileUpload({  
  48.         url : Util.getContentPath() + '/user/uploadHeaderPicTmp.do?inputId=realPicFile',//用于文件上传的服务器端请求地址    
  49.         secureuri : false,//一般设置为false    
  50.         fileElementId : 'realPicFile',//文件上传空间的id属性  <input type="file" id="file" name="file" />    
  51.         dataType : 'json',//返回值类型 一般设置为json    
  52.         success : function(data, status) //服务器成功响应处理函数    
  53.         {     
  54.             // 图片在服务器上的相对地址,加随机数防止不刷新  
  55.             path = Util.getContentPath() + data.path + "?" + Math.random();  
  56.             $("#realPic").attr("src", path);  
  57.             var imgs = $(".jcrop-holder").find("img");  
  58.             // 原本有图片,重新上传后,所有的img都需要刷新  
  59.             imgs.each(function (i, v) {  
  60.                 $(this).attr("src", path);  
  61.             });  
  62.             $('#preview-pane .preview-container img').attr("src", path);  
  63.               
  64.             // 切图样式  
  65.             // Grab some information about the preview pane  
  66.             $preview = $('#preview-pane'), $pcnt = $('#preview-pane .preview-container'), $pimg = $('#preview-pane .preview-container img'),  
  67.             xsize = $pcnt.width(), ysize = $pcnt.height();  
  68.             //console.log('init', [ xsize, ysize ]);  
  69.               
  70.             $('#realPic').Jcrop({  
  71.                 onChange : updatePreview, //切图框改变事件  
  72.                 onSelect : updatePreview, // 切图框选择事件  
  73.                 onRelease: clearCoords, // 切图框释放的事件  
  74.                 bgFade   : true,  
  75.                 bgOpacity: .8, // 截图框以外部分的透明度  
  76.                 setSelect: [10, 10, 100, 100], // 默认选择的区域  
  77.             aspectRatio : 1 //xsize / ysize 截图比例,这里我采用1 : 1 的比例,即切出来的为正方形  
  78.             }, function() {  
  79.                 // Use the API to get the real image size  
  80.                 var bounds = this.getBounds();  
  81.                 boundx = bounds[0];  
  82.                 boundy = bounds[1];  
  83.                 // Store the API in the jcrop_api variable  
  84.                 jcrop_api = this;  
  85.                 // Move the preview into the jcrop container for css positioning  
  86.                 $preview.appendTo(jcrop_api.ui.holder);  
  87.             });  
  88.         },  
  89.         error : function(data, status, e)//服务器响应失败处理函数    
  90.         {  
  91.             Error(e);  
  92.         }  
  93.     });  
  94.     return false;  
  95. }  
  96.   
  97. function _getShowWidth(str) {  
  98.     return _getValue(str, "width");  
  99. }  
  100.   
  101. function _getShowHeight(str) {  
  102.     return _getValue(str, "height");  
  103. }  
  104.   
  105. function _getValue (str, key) {  
  106.     var str = str.replace(/\:|\;|\s/g, '').toLowerCase();  
  107.     var pos = str.indexOf(key);  
  108.     if (pos >= 0) {  
  109.         // 截取  
  110.         var tmp = str.substring(pos, str.length);  
  111.         var px = tmp.indexOf("px");  
  112.         if (px > 0){  
  113.             var width = tmp.substring(key.length, px);  
  114.             return width;  
  115.         }  
  116.         return 0;  
  117.     }  
  118.     return 0;  
  119. }  
  120.   
  121. /** 
  122.  * 裁剪图片 
  123.  */  
  124. function cutPic() {  
  125.     // 初始化数据  
  126.     var x1 = $('#x1').val() == "" ? 0 : $('#x1').val();  
  127.     var y1 = $('#y1').val() == "" ? 0 : $('#y1').val();  
  128.     var x2 = $('#x2').val();  
  129.     var y2 = $('#y2').val();  
  130.     var w = $('#w').val() == "" ? 150 : $('#w').val();  
  131.     var h= $('#h').val() == "" ? 150 : $('#h').val();  
  132.       
  133.     var srcFile = $("#realPic").attr("src");  
  134.     if (srcFile == "" || !srcFile) {  
  135.         Error("没有选择任何图片.");  
  136.         return;  
  137.     }  
  138.        
  139.     var showDiv = $(".jcrop-holder > .jcrop-tracker");  
  140.     // 从压缩存放图片的div中获取压缩后显示的宽度和高度,用来交给后台同比例进行裁剪  
  141.     // width: 404px; height: 304px; position: absolute; top: -2px; left: -2px; z-index: 290; cursor: crosshair;  
  142.     var style = showDiv.attr("style");  
  143.     // 原图片页面显示的宽度  
  144.     var showWidth = _getShowWidth(style);  
  145.     // 原图片页面显示的高度  
  146.     var showHeight = _getShowHeight(style);  
  147.     // console.log(showWidth + " " + showHeight);  
  148.     // 原地图的src地址,去掉后边防止不刷新的随机数  
  149.     srcFile = srcFile.substring(0, srcFile.indexOf("?"));  
  150.     $.ajax({  
  151.         type : "post",  
  152.         dataType : "json",  
  153.         url : Util.getContentPath() + "/user/uploadHeaderPic.do",  
  154.         data : {  
  155.             srcImageFile : srcFile,  
  156.             x : x1,  
  157.             y : y1,  
  158.             destWidth : w,  
  159.             destHeight : h,  
  160.             srcShowWidth : showWidth,  
  161.             srcShowHeight : showHeight,  
  162.         },  
  163.         success : function(data) {  
  164.             var okCallBack = function () {  
  165.                 this.top.window.location = Util.getContentPath() + "/user/pcModiInfoInit.do";  
  166.             };  
  167.             var msg = eval(data);  
  168.             if(msg && msg.msg)  
  169.                 if (msg.code == 1)  
  170.                     Alert(msg.msg, okCallBack);  
  171.                 else Error(msg.msg, okCallBack);  
  172.             else {  
  173.                 Error("上传失败,请稍后重试.", okCallBack);  
  174.                 return;  
  175.             }  
  176.         },  
  177.         error : function () {  
  178.             Error ("上传失败,请稍后重试.") ;  
  179.         }  
  180.     });  
  181. }  
  182.   
  183. function clearCoords()  
  184. {  
  185.   $('#coords input').val('');  
  186. };  

(3)springMVC代码:

[java] view plaincopyprint?
  1. @RequestMapping("uploadHeaderPicTmp")  
  2.     @ResponseBody  
  3.     public String uploadHeaderPic(String inputId, MultipartHttpServletRequest request) {  
  4.         try {  
  5.             MultipartFile realPicFile = request.getFile(inputId);  
  6.             InputStream in = realPicFile.getInputStream();  
  7.             String path = request.getSession().getServletContext().getRealPath("/");  
  8.             path += TMP;  
  9.             User loginUser = SystemUtil.getLoginUser(request.getSession());  
  10.             String fileName = loginUser.getName() + "." + FilenameUtils.getExtension(realPicFile.getOriginalFilename());  
  11.             File f = new File(path + "/" + fileName);  
  12.             FileUtils.copyInputStreamToFile(in, f);  
  13.             return "{\"path\" : \"" + TMP + "/" + fileName + "\"}";  
  14.         } catch (Exception e) {  
  15.             LOG.error("upload header picture error : ", e);  
  16.         }  
  17.         return null;  
  18.     }  
  19.   
  20.     @RequestMapping("uploadHeaderPic")  
  21.     @ResponseBody  
  22.     public GeneralMessage cutImage(String srcImageFile, int x, int y, int destWidth, int destHeight, int srcShowWidth, int srcShowHeight,  
  23.             HttpServletRequest request) {  
  24.         try {  
  25.             String path = request.getSession().getServletContext().getRealPath("/");  
  26.             Image img;  
  27.             ImageFilter cropFilter;  
  28.             String srcFileName = FilenameUtils.getName(srcImageFile);  
  29.             // 读取源图像    
  30.             File srcFile = new File(path + TMP + "/" + srcFileName);  
  31.   
  32.             BufferedImage bi = ImageIO.read(srcFile);  
  33.             //前端页面显示的并非原图大小,而是经过了一定的压缩,所以不能使用原图的宽高来进行裁剪,需要使用前端显示的图片宽高  
  34.             int srcWidth = bi.getWidth(); // 源图宽度    
  35.             int srcHeight = bi.getHeight(); // 源图高度  
  36.             if (srcShowWidth == 0)  
  37.                 srcShowWidth = srcWidth;  
  38.             if (srcShowHeight == 0)  
  39.                 srcShowHeight = srcHeight;  
  40.   
  41.             if (srcShowWidth >= destWidth && srcShowHeight >= destHeight) {  
  42.                 Image image = bi.getScaledInstance(srcShowWidth, srcShowHeight, Image.SCALE_DEFAULT);//获取缩放后的图片大小    
  43.                 cropFilter = new CropImageFilter(x, y, destWidth, destHeight);  
  44.                 img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(), cropFilter));  
  45.                 BufferedImage tag = new BufferedImage(destWidth, destHeight, BufferedImage.TYPE_INT_RGB);  
  46.                 Graphics g = tag.getGraphics();  
  47.                 g.drawImage(img, 00null); // 绘制截取后的图    
  48.                 g.dispose();  
  49.   
  50.                 String ext = FilenameUtils.getExtension(srcImageFile);  
  51.   
  52.                 path += HEADER_PIC;  
  53.                 User loginUser = SystemUtil.getLoginUser(request.getSession());  
  54.                 String fileName = loginUser.getName() + "." + ext;  
  55.                 File destImageFile = new File(path + "/" + fileName);  
  56.                 // 输出为文件    
  57.                 ImageIO.write(tag, ext, destImageFile);  
  58.   
  59.                 loginUser.setPicPath(SystemConst.SYSTEM_CONTEXT_PATH_VALUE + HEADER_PIC + "/" + fileName);  
  60.                 userService.update(loginUser);  
  61.                 // 删除原临时文件  
  62.                 srcFile.delete();  
  63.   
  64.                 GeneralMessage msg = new GeneralMessage();  
  65.                 msg.setCode(GeneralMessage.SUCCESS);  
  66.                 msg.setMsg("上传成功!");  
  67.                 return msg;  
  68.             }  
  69.         } catch (Exception e) {  
  70.             e.printStackTrace();  
  71.         }  
  72.         return null;  
  73.     } 
0 1
原创粉丝点击