头像裁剪上传功能,用到的技术有  jquery,springmvc,裁剪插件用的是jcrop(中间遇到很多坑,最终跨越)。由于保密性我不能将别的源码发送到网上,请大家见谅。

图片上传步骤:

1.用户选择图片

2.将图片传入后台:用户选择图片的时候选择的是各种各样的,但是我们的网页显示图片大小是有限的,所以我们就要在用户选择图片之后将图片添加到后台进行压缩,压缩成我们想要的大小,之后再显示到页面才好

3.利用jcrop裁剪工具对图片进行裁剪并且实时预览

4.点击确定按钮将裁剪用到的参数传入后台,后台图片进行剪切,之后缩放成我们需要的格式

5.最后将图片路径传到前台进行展示


前台页面代码为:

<script src="js-jcrop/jquery.min.js"></script>
<script src="js-jcrop/jquery.Jcrop.js"></script>
<script src="js/jquery-form.js"></script>
<link rel="stylesheet" href="../css/jquery.Jcrop.css" type="text/css" />
<style type="text/css">
/* 控制预览区域大小*/
#preview-pane .preview-container {
  width: 110px;
  height: 110px;
  overflow: hidden;
}
#targetDiv{
  width: 400px;
  height: 400px;
  background-color:#f7fdff;
}
</style>

<dl class="dialogBox D_uploadLogo">
	<dt class="dialogHeader">
		<span class="title">头像上传</span>
	</dt>
	
	<dd class="dialogBody">
		<dl class="bisinessLogo">
			<dt class="title">预览</dt>
			<dd class="img">
				<div id="preview-pane">
				    <div class="preview-container">
				      <img src="" id="target2" class="jcrop-preview" alt="未选择图片" />
				    </div>
				 </div>
			</dd>
			<dd class="tc">尺寸:110*110px</dd>
		</dl>
		<dl class="bisinessInfo">
			<dt class="btnBox02">
				<form id="fileUp" action="/file/img/upload" method="post" enctype="multipart/form-data" target="ifm">
					<a class="btnGray" href="javascript:;">
						<span class="text" id="format">选择图片</span>  
						<b class="bgR"></b>
						<input type="file" id="file_upload" class="inputFile" name="userphoto"/>
						<input type="hidden" id="w" name="w"/>
						<input type="hidden" id="h" name="h"/>
						<input type="hidden" id="x" name="x"/>
						<input type="hidden" id="y" name="y"/>
					</a>
				</form>
			</dt>
			<dd class="info">
			
				请从本地选择一张照片,支持jpg,png格式    <span id="msg"></span>
				<div id="targetDiv">
					<img src="" id="target" width="400" height="400" alt="未选择图片"/>
				</div>
			</dd>
		</dl>
	</dd>
	<input type="hidden" id="filePathInput" value=""/>

	<dd class="dialogBottom">
		<a class="btnBlue btn_confirm" href="javascript:;" οnclick="photoSummit();"><span class="text">确定</span><b class="bgR"></b></a>
		<a class="btnGray btn_cancel" href="javascript:;" οnclick="hideDialog();"><span class="text">取消</span><b class="bgR"></b></a>
	</dd>
</dl>





1.选择图片

<img src="" id="target" width="400" height="400" alt="未选择图片"/>

2.提交:首先大家知道文件上传的时候用到的标签为:<input type="file"/>   但是有时候我们需要用ajax提交文件并且异步提交,我们如果是用form表单提交的话就不是异步,这样我们回到页面就刷新页面,非常的不方便,但是现在ajax还不能支持文件提交的方式,这时候我们就用到了jquery-form.js,这个文件支持我们用ajax提交文件,代码为:

$("#fileUp").<span style="color:#ff0000;">ajaxSubmit</span>({
			type: "POST",
			url:"/file/img/upload",
			dataType: "json",
			contentType:"application/json", 
		        success: function(parameter){
		     	$("#target2").attr('src','/upload/'+parameter.fileName);
		     	$("#filePathInput").val('/upload/'+parameter.fileName);
		     	if($("#format").text()=="重新上传"){
		     		jcrop_api.destroy()
		     	}
		     	$("#format").text("重新上传");
		     	//启动jcrop支持
		     	openJcrop('/upload/'+parameter.fileName);
			},
	        error : function(data) {  
	            alert("ajax传输发生错误!!!");
	        } 
		 });

这样就能将文件用ajax的方式提交到后台,注意这里用的是ajaxSubmit,这个方法对应jquery-form.js,后台代码为:

package com.quanshi.ums.gate.view.rest.controllers;


import java.io.IOException;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 com.quanshi.ums.gate.persistence.entities.Parameters;
import com.quanshi.ums.gate.view.rest.ImgEditor;




/**
 * 图像上传和修改相关类
 * @author kunpeng.zhao
 *
 */
@Controller
@RequestMapping(value="/file")
public class FileEditorController {
<span style="white-space:pre">	</span>ImgEditor imgEditor = new ImgEditor();
<span style="white-space:pre">	</span>public String filePathFinal = "";
<span style="white-space:pre">	</span>private Logger logger = LoggerFactory.getLogger(FileEditorController.class);
<span style="white-space:pre">	</span>@RequestMapping(value="/img/cutandscale",method=RequestMethod.POST)
<span style="white-space:pre">	</span>public @ResponseBody int cutAndscaleimg(
<span style="white-space:pre">			</span>@RequestParam("w") int w,
<span style="white-space:pre">			</span>@RequestParam("h") int h,
<span style="white-space:pre">			</span>@RequestParam("x") int x,
<span style="white-space:pre">			</span>@RequestParam("y") int y
<span style="white-space:pre">			</span>){
<span style="white-space:pre">		</span>imgEditor.cut(filePathFinal,filePathFinal,x,y,w,h);
<span style="white-space:pre">		</span>imgEditor.scale(filePathFinal, filePathFinal, 110, 110, false);
<span style="white-space:pre">		</span>return 1;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>
    @RequestMapping(value="/img/upload",method=RequestMethod.POST)
    public @ResponseBody Parameters addImage(
    <span style="white-space:pre">		</span>@RequestParam("userphoto") MultipartFile file,
    <span style="white-space:pre">		</span>HttpServletRequest request,
    <span style="white-space:pre">		</span>HttpServletResponse response,
    <span style="white-space:pre">		</span>HttpSession session
    <span style="white-space:pre">		</span>){
    <span style="white-space:pre">	</span>String filePath = ""; 
    <span style="white-space:pre">	</span>try {
    <span style="white-space:pre">		</span>//上传原图
<span style="white-space:pre">			</span>filePath = imgEditor.uploadFile(file, request,session);
<span style="white-space:pre">			</span>filePathFinal = filePath;
<span style="white-space:pre">			</span>//将图片压缩成指定大小
<span style="white-space:pre">			</span>imgEditor.zoomImage(filePath,filePath,400,400);
<span style="white-space:pre">		</span>} catch (IOException e) {
<span style="white-space:pre">			</span>e.printStackTrace();
<span style="white-space:pre">		</span>}  
        logger.info("filePath:" + filePath);
        Parameters parameter = new Parameters();
        parameter.setFileName(imgEditor.getFileName(file,request,session));
    <span style="white-space:pre">	</span>return parameter;
    }
    
    
   
    
}

我在这规定图片在前台展示的大小为400*400,用到的图片裁剪压缩等的工具类为:

package com.quanshi.ums.gate.view.rest;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.multipart.MultipartFile;

public class ImgEditor {
	 /**
     * 改变图片尺寸
     * @param srcFileName 源图片路径
     * @param tagFileName 目的图片路径
     * @param width 修改后的宽度
     * @param height 修改后的高度
     */
    public void zoomImage(String srcFileName,String tagFileName,int width,int height){  
	     try {
	      BufferedImage bi = ImageIO.read(new File(srcFileName));
	      BufferedImage tag=new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);
	      tag.getGraphics().drawImage(bi, 0, 0, width, height, null);
	      ImageIO.write(tag, "jpg", new File(tagFileName));//画图
	     } catch (IOException e) {
	      e.printStackTrace();
	     }
    }
    
    
    
    /**
     * 缩放图像(按高度和宽度缩放)
     * @param srcImageFile 源图像文件地址
     * @param result 缩放后的图像地址
     * @param height 缩放后的高度
     * @param width 缩放后的宽度
     * @param bb 比例不对时是否需要补白:true为补白; false为不补白;
     */
    public void scale(String srcImageFile, String result, int height, int width, boolean bb) {
        try {
            double ratio = 0.0; // 缩放比例
            File f = new File(srcImageFile);
            BufferedImage bi = ImageIO.read(f);
            Image itemp = bi.getScaledInstance(width, height, bi.SCALE_SMOOTH);
            // 计算比例
            if ((bi.getHeight() > height) || (bi.getWidth() > width)) {
                if (bi.getHeight() > bi.getWidth()) {
                    ratio = (new Integer(height)).doubleValue()
                            / bi.getHeight();
                } else {
                    ratio = (new Integer(width)).doubleValue() / bi.getWidth();
                }
                AffineTransformOp op = new AffineTransformOp(AffineTransform
                        .getScaleInstance(ratio, ratio), null);
                itemp = op.filter(bi, null);
            }
            if (bb) {//补白
                BufferedImage image = new BufferedImage(width, height,
                        BufferedImage.TYPE_INT_RGB);
                Graphics2D g = image.createGraphics();
                g.setColor(Color.white);
                g.fillRect(0, 0, width, height);
                if (width == itemp.getWidth(null))
                    g.drawImage(itemp, 0, (height - itemp.getHeight(null)) / 2,
                            itemp.getWidth(null), itemp.getHeight(null),
                            Color.white, null);
                else
                    g.drawImage(itemp, (width - itemp.getWidth(null)) / 2, 0,
                            itemp.getWidth(null), itemp.getHeight(null),
                            Color.white, null);
                g.dispose();
                itemp = image;
            }
            ImageIO.write((BufferedImage) itemp, "JPEG", new File(result));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    
    /**
     * 图像切割(按指定起点坐标和宽高切割)
     * @param srcImageFile 源图像地址
     * @param result 切片后的图像地址
     * @param x 目标切片起点坐标X
     * @param y 目标切片起点坐标Y
     * @param width 目标切片宽度
     * @param height 目标切片高度
     */
    public void cut(String srcImageFile, String result,
            int x, int y, int width, int height) {
        try {
            // 读取源图像
            BufferedImage bi = ImageIO.read(new File(srcImageFile));
            int srcWidth = bi.getHeight(); // 源图宽度
            int srcHeight = bi.getWidth(); // 源图高度
            if (srcWidth > 0 && srcHeight > 0) {
                Image image = bi.getScaledInstance(srcWidth, srcHeight,
                        Image.SCALE_DEFAULT);
                // 四个参数分别为图像起点坐标和宽高
                // 即: CropImageFilter(int x,int y,int width,int height)
                ImageFilter cropFilter = new CropImageFilter(x, y, width, height);
                Image img = Toolkit.getDefaultToolkit().createImage(
                        new FilteredImageSource(image.getSource(),
                                cropFilter));
                BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                Graphics g = tag.getGraphics();
                g.drawImage(img, 0, 0, width, height, null); // 绘制切割后的图
                g.dispose();
                // 输出为文件
                ImageIO.write(tag, "JPEG", new File(result));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获得文件名字
	public String getFileName(MultipartFile file, HttpServletRequest request,HttpSession session){
		String FILE_PATH = session.getServletContext().getRealPath("/") + "upload";
        String fileName = file.getOriginalFilename();  
        String[] suffixNameArr = fileName.split("\\.");
        String suffixName = suffixNameArr[suffixNameArr.length-1];
        String userName = SecurityContextHolder.getContext().getAuthentication().getName();
        
		return getTime() + userName+"."+suffixName;
	}
    //文件上传,返回文件路径
    public String uploadFile(MultipartFile file, HttpServletRequest request,HttpSession session) throws IOException {
    	String FILE_PATH = session.getServletContext().getRealPath("/") + "upload";
    	String fileName = getFileName(file,request,session);
        File tempFile = new File(FILE_PATH, fileName); 
        
        if (!tempFile.getParentFile().exists()) {  
            tempFile.getParentFile().mkdir();  
        }  
        if (!tempFile.exists()) {  
            tempFile.createNewFile();  
        }  
        file.transferTo(tempFile);  //将上传文件写到服务器上指定的文件。
        
        return FILE_PATH + "\\" + tempFile.getName();  
    }  
  
   /* public static File getFile(String fileName) {  
        return new File(FILE_PATH, fileName);  
    } */ 
    
    public String getTime(){
    	Date date = new Date();
    	SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式
    	String nowTime = df.format(date).toString();
    	return nowTime;
    }
}

这样就将图片要裁剪的图片路径返回页面展示

3.之后就是图片裁剪了,图片裁剪功能我找了好多插件,最后锁定jcrop,也是因为它的demo打动了我(太好看了),之后就是导入文件,至于这个裁剪工具具体的运用的话大家请参考这篇博文,当然这是被人写的非常好,还有api可以看,  在我这里,我在页面接收后台返回来的图片路径之后启用jcrop,也就是openJcrop()方法,这样就可以加载jcrop插件了,具体大家想进一步了解这个裁剪工具,请到官网细细的研究,我就不再做过多的谈论了。

大家注意,在这里有个大坑,真的是大坑,就是重新选择图片的时候,被jcrop加载过的img的src是不能被修改的,这个当初卡了我好长时间,被jcrop加载一次jcrop就会生成一个自己的编辑对象(我自己的理解),这时候就和原来的img没有关系了,直到最后细细研究api才找到了一个方法,唯一的方法就是将这个jcrop销毁,就是jcrop_api.destroy(),这个有很大的学问,我就提示一点,就是将jcrop_api声明为全局变量,下面贴出js代码(和上边的html是在一个文件下):

<script type="text/javascript">
   	
	 $(function(){
	 	var jcrop_api;
	 });
	
	 $("#file_upload").change(function() {
	 	 $("#msg").text('');
		 var oFile = $(this)[0].files[0];
		 //判断上传文件大小
	     if (oFile.size > 1*1024*1024) {
	          $("#msg").text('你选择了太大的文件,请选择一个1M以下的图像文件').css('color','red');
	          $(this).val("");
	          return;
	     }
    	   
    	  //判断类型
    	  var filepath=$(this).val();
		  var extStart=filepath.lastIndexOf(".");
		  var ext=filepath.substring(extStart,filepath.length).toUpperCase();
		  if(ext!=".JPEG"&&ext!=".PNG"&&ext!=".JPG"){
		  	$("#msg").text('请选择一个有效的图像文件(jpg,png是允许的)').css('color','red');
		        $(this).val("");
		        return;
		  }
			
		$("#fileUp").ajaxSubmit({
			type: "POST",
			url:"/file/img/upload",
			dataType: "json",
			contentType:"application/json", 
		    success: function(parameter){
		     	$("#target2").attr('src','/upload/'+parameter.fileName);
		     	$("#filePathInput").val('/upload/'+parameter.fileName);
		     	if($("#format").text()=="重新上传"){
		     		jcrop_api.destroy()
		     	}
		     	$("#format").text("重新上传");
		     	//启动jcrop支持
		     	openJcrop('/upload/'+parameter.fileName);
			},
	        error : function(data) {  
	            alert("ajax传输发生错误!!!");
	        } 
		 });
	});
	 function photoSummit(){
	 
		 //alert($("#w").val()+","+$("#h").val()+","+$("#x").val()+","+$("#y").val());
		 //$("#fileUp").attr("action", "/file/img/upload").submit();
		 if($("#w").val()>0 && $("#h").val()>0){
		 	$("#fileUp").ajaxSubmit({
				type: "POST",
				url:"/file/img/cutandscale",
				dataType: "json",
				contentType:"application/json", 
			    success: function(data){
			    	 $("#msg").text('上传头像成功!!!').css('color','red');
			    	 //alert($("#filePathInput").val());
			    	 window.parent.back($("#filePathInput").val());
				},  
			    error : function(data) {  
			        alert("ajax传输发生错误!!!");
			    } 
		    });
		 }else{
		 	$("#msg").text('请用鼠标截取图片').css('color','red');
		 }  
	 }
	 //启动jcrop
	function openJcrop(imgPath){
		//启动jcrop支持
				var boundx,boundy,
		        xsize = $('#preview-pane .preview-container').width(),
		        ysize = $('#preview-pane .preview-container').height();
		        
			    $('#target').Jcrop({
			      minSize: [110, 110],
			      onChange: updatePreview,
			      onSelect: updatePreview,
			      aspectRatio: xsize / ysize
			    },function(){
			      // Use the API to get the real image size
			      var bounds = this.getBounds();
			      boundx = bounds[0];
			      boundy = bounds[1];
			      jcrop_api = this;
			    });
				jcrop_api.setImage(imgPath);
			    function updatePreview(c)
			    {
			      if (parseInt(c.w) > 0)
			      {
			        var rx = xsize / c.w;
			        var ry = ysize / c.h;
			
			        $('#preview-pane .preview-container img').css({
			          width: Math.round(rx * boundx) + 'px',
			          height: Math.round(ry * boundy) + 'px',
			          marginLeft: '-' + Math.round(rx * c.x) + 'px',
			          marginTop: '-' + Math.round(ry * c.y) + 'px'
			        });
			        $("#w").val(c.w);
			        $("#h").val(c.h);
			        $("#x").val(c.x);
			        $("#y").val(c.y);
			      }
			     };
	}
	 
	 
</script>



这样我们就完成了编辑功能,之后我们点击提交就会将w,h,x,y参数传到后台,这个whxy表示我用一个在网上下载的图片来表示:


4.传到后台之后的代码在上面我已经贴出,不做过多解释,大家自己理解,不懂的可以给我留言


整篇博文纯手打,如果大家觉得幼稚的借鉴的地方请给个赞,工作时候抽出时间比较难,但还是谢了这篇博文,如果谁发现bug或者不对的地方请随时联系我,大家互相交流提高。